Skip to content

Commit 3c3c509

Browse files
committed
Merge #8: Allow correct behavior of 'parse_size' and 'format_size'
2 parents 2d02cbc + a54b07a commit 3c3c509

File tree

2 files changed

+28
-4
lines changed

2 files changed

+28
-4
lines changed

humanfriendly/__init__.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@
5959
dict(prefix='t', divider=1024**4, singular='TB', plural='TB'),
6060
dict(prefix='p', divider=1024**5, singular='PB', plural='PB'))
6161

62+
# Common disk size units based on IEEE 1541.
63+
disk_size_units_ieee = (dict(prefix='b', divider=1, singular='byte', plural='bytes'),
64+
dict(prefix='k', divider=1000**1, singular='KB', plural='KB'),
65+
dict(prefix='m', divider=1000**2, singular='MB', plural='MB'),
66+
dict(prefix='g', divider=1000**3, singular='GB', plural='GB'),
67+
dict(prefix='t', divider=1000**4, singular='TB', plural='TB'),
68+
dict(prefix='p', divider=1000**5, singular='PB', plural='PB'))
69+
6270
# Common length size units, used for formatting and parsing.
6371
length_size_units = (dict(prefix='nm', divider=1e-09, singular='nm', plural='nm'),
6472
dict(prefix='mm', divider=1e-03, singular='mm', plural='mm'),
@@ -104,7 +112,7 @@ def coerce_boolean(value):
104112
return bool(value)
105113

106114

107-
def format_size(num_bytes, keep_width=False):
115+
def format_size(num_bytes, keep_width=False, correct=False):
108116
"""
109117
Format a byte count as a human readable file size.
110118
@@ -128,15 +136,20 @@ def format_size(num_bytes, keep_width=False):
128136
'1 MB'
129137
>>> format_size(1024 ** 3 * 4)
130138
'4 GB'
139+
>>> format_size(1000 ** 3 * 4, correct=True)
140+
'4 GB'
131141
"""
132-
for unit in reversed(disk_size_units):
142+
units = disk_size_units
143+
if correct:
144+
units = disk_size_units_ieee
145+
for unit in reversed(units):
133146
if num_bytes >= unit['divider']:
134147
number = round_number(float(num_bytes) / unit['divider'], keep_width=keep_width)
135148
return pluralize(number, unit['singular'], unit['plural'])
136149
return pluralize(num_bytes, 'byte')
137150

138151

139-
def parse_size(size):
152+
def parse_size(size, correct=False):
140153
"""
141154
Parse a human readable data size and return the number of bytes.
142155
@@ -155,6 +168,8 @@ def parse_size(size):
155168
5120
156169
>>> parse_size('1.5 GB')
157170
1610612736
171+
>>> parse_size('1.5 GB', correct=True)
172+
1500000000
158173
"""
159174
tokens = tokenize(size)
160175
if tokens and isinstance(tokens[0], numbers.Number):
@@ -165,7 +180,10 @@ def parse_size(size):
165180
if len(tokens) == 2 and is_string(tokens[1]):
166181
normalized_unit = tokens[1].lower()
167182
# Try to match the first letter of the unit.
168-
for unit in disk_size_units:
183+
units = disk_size_units
184+
if correct:
185+
units = disk_size_units_ieee
186+
for unit in units:
169187
if normalized_unit.startswith(unit['prefix']):
170188
return int(tokens[0] * unit['divider'])
171189
# We failed to parse the size specification.

humanfriendly/tests.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ def test_format_size(self):
190190
self.assertEqual('1 GB', humanfriendly.format_size(1024 ** 3))
191191
self.assertEqual('1 TB', humanfriendly.format_size(1024 ** 4))
192192
self.assertEqual('1 PB', humanfriendly.format_size(1024 ** 5))
193+
self.assertEqual('1 byte', humanfriendly.format_size(1, correct=True))
194+
self.assertEqual('45 KB', humanfriendly.format_size(1000 * 45, correct=True))
195+
self.assertEqual('1 GB', humanfriendly.format_size(1000 ** 3, correct=True))
196+
self.assertEqual('2.9 TB', humanfriendly.format_size(1000 ** 4 * 2.9, correct=True))
193197

194198
def test_parse_size(self):
195199
"""Test :func:`humanfriendly.parse_size()`."""
@@ -203,6 +207,8 @@ def test_parse_size(self):
203207
self.assertEqual(1024 ** 3 * 1.5, humanfriendly.parse_size('1.5 GB'))
204208
self.assertRaises(humanfriendly.InvalidSize, humanfriendly.parse_size, '1z')
205209
self.assertRaises(humanfriendly.InvalidSize, humanfriendly.parse_size, 'a')
210+
self.assertEqual(1000, humanfriendly.parse_size('1 KB', correct=True))
211+
self.assertEqual(1000 ** 2 * 69, humanfriendly.parse_size('69 MB', correct=True))
206212

207213
def test_format_length(self):
208214
"""Test :func:`humanfriendly.format_length()`."""

0 commit comments

Comments
 (0)