1import locale
2from natural.constant import FILESIZE_SUFFIX
3from natural.number import _format
4
5FILESIZE_BASE = dict(
6    decimal=1024,
7    binary=1000,
8    gnu=1024,
9)
10
11
12def filesize(value, format='decimal', digits=2):
13    '''
14    Convert a file size into natural readable format. Multiple formats are
15    supported.
16
17    :param value: size
18    :param format: default ``decimal``, choices ``binary``, ``decimal`` or
19                   ``gnu``
20    :param digits: default ``2``
21
22    >>> filesize(123)
23    '123.00 B'
24    >>> filesize(123456)
25    '120.56 kB'
26    >>> filesize(1234567890)
27    '1.15 GB'
28    '''
29
30    if format not in FILESIZE_SUFFIX:
31        raise TypeError
32
33    base = FILESIZE_BASE[format]
34    size = int(value)
35    sign = size < 0 and u'-' or ''
36    size = abs(size)
37
38    for i, suffix in enumerate(FILESIZE_SUFFIX[format]):
39        unit = base ** (i + 1)
40        if size < unit:
41            result = u''.join([
42                sign,
43                _format(base * size / float(unit), digits),
44                u' ',
45                suffix,
46            ])
47            if format == 'gnu':
48                result = result.replace(' ', '')
49            return result
50
51    raise OverflowError
52
53
54def decimalsize(value):
55    '''
56    Wrapper for :py:func:`filesize`.
57
58    >>> decimalsize(123)
59    '123.00 B'
60    >>> decimalsize(123456)
61    '120.56 kB'
62    >>> decimalsize(1234567890)
63    '1.15 GB'
64    '''
65    return filesize(value, format='decimal')
66
67
68def binarysize(value):
69    '''
70    Wrapper for :py:func:`filesize`.
71
72    >>> binarysize(123)
73    '123.00 iB'
74    >>> binarysize(123456)
75    '123.46 KiB'
76    >>> binarysize(1234567890)
77    '1.23 GiB'
78    '''
79    return filesize(value, format='binary')
80
81
82def gnusize(value, digits=1):
83    '''
84    Wrapper for :py:func:`filesize`.
85
86    >>> gnusize(123)
87    '123.0B'
88    >>> gnusize(123456)
89    '120.6K'
90    >>> gnusize(1234567890)
91    '1.1G'
92    '''
93    return filesize(value, format='gnu', digits=digits)
94