1"""Functions for reporting filesizes. Borrowed from https://github.com/PyFilesystem/pyfilesystem2
2
3The functions declared in this module should cover the different
4use cases needed to generate a string representation of a file size
5using several different units. Since there are many standards regarding
6file size units, three different functions have been implemented.
7
8See Also:
9 * `Wikipedia: Binary prefix <https://en.wikipedia.org/wiki/Binary_prefix>`_
10
11"""
12
13__all__ = ["decimal"]
14
15from typing import Iterable, List, Optional, Tuple
16
17
18def _to_str(
19 size: int,
20 suffixes: Iterable[str],
21 base: int,
22 *,
23 precision: Optional[int] = 1,
24 separator: Optional[str] = " ",
25) -> str:
26 if size == 1:
27 return "1 byte"
28 elif size < base:
29 return f"{size:,} bytes"
30
31 for i, suffix in enumerate(suffixes, 2): # noqa: B007
32 unit = base**i
33 if size < unit:
34 break
35 return "{:,.{precision}f}{separator}{}".format(
36 (base * size / unit),
37 suffix,
38 precision=precision,
39 separator=separator,
40 )
41
42
43def pick_unit_and_suffix(size: int, suffixes: List[str], base: int) -> Tuple[int, str]:
44 """Pick a suffix and base for the given size."""
45 for i, suffix in enumerate(suffixes):
46 unit = base**i
47 if size < unit * base:
48 break
49 return unit, suffix
50
51
52def decimal(
53 size: int,
54 *,
55 precision: Optional[int] = 1,
56 separator: Optional[str] = " ",
57) -> str:
58 """Convert a filesize in to a string (powers of 1000, SI prefixes).
59
60 In this convention, ``1000 B = 1 kB``.
61
62 This is typically the format used to advertise the storage
63 capacity of USB flash drives and the like (*256 MB* meaning
64 actually a storage capacity of more than *256 000 000 B*),
65 or used by **Mac OS X** since v10.6 to report file sizes.
66
67 Arguments:
68 int (size): A file size.
69 int (precision): The number of decimal places to include (default = 1).
70 str (separator): The string to separate the value from the units (default = " ").
71
72 Returns:
73 `str`: A string containing a abbreviated file size and units.
74
75 Example:
76 >>> filesize.decimal(30000)
77 '30.0 kB'
78 >>> filesize.decimal(30000, precision=2, separator="")
79 '30.00kB'
80
81 """
82 return _to_str(
83 size,
84 ("kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"),
85 1000,
86 precision=precision,
87 separator=separator,
88 )