Skip to content

Commit 83a8170

Browse files
authored
Merge pull request #114 from timlnx/bitbyte-whatever
Byte/Bit display abbreviations and base-unit parse_string fixes
2 parents 6a71b85 + 3472fb9 commit 83a8170

9 files changed

Lines changed: 81 additions & 39 deletions

File tree

NEWS.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ Breaking Changes
4949
``setup.py`` and ``setup.py.in`` are gone. Installation is
5050
``pip install bitmath``. Source builds use ``python -m build``.
5151

52+
**Byte and Bit display names**
53+
``Byte`` and ``Bit`` now display as ``B`` and ``b`` respectively,
54+
matching the abbreviated style of every other unit. Code that
55+
compares formatted strings (e.g. ``"{unit}"`` in a format template
56+
or the output of ``str()`` / ``repr()``) against the literal words
57+
``"Byte"`` or ``"Bit"`` will need to be updated. The class names
58+
themselves are unchanged.
59+
5260

5361
Library Improvements
5462
====================

bitmath/__init__.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,7 @@ def __abs__(self):
10221022
class Byte(Bitmath):
10231023
"""Byte based types fundamentally operate on self._bit_value"""
10241024
def _setup(self):
1025-
return (2, 0, 'Byte', 'Bytes')
1025+
return (2, 0, 'B', 'B')
10261026

10271027
######################################################################
10281028
# NIST Prefixes for Byte based types
@@ -1167,7 +1167,7 @@ def _set_prefix_value(self):
11671167
self.prefix_value = self._to_prefix_value(self._bit_value)
11681168

11691169
def _setup(self):
1170-
return (2, 0, 'Bit', 'Bits')
1170+
return (2, 0, 'b', 'b')
11711171

11721172
def _norm(self, value):
11731173
"""Normalize the input value into the fundamental unit for this prefix
@@ -1583,6 +1583,14 @@ def parse_string(s, system=NIST, strict=True):
15831583

15841584
val, unit = s[:index], s[index:]
15851585

1586+
# Explicit base-unit and word-form checks: handle B, b, bit(s),
1587+
# byte(s) before the prefix-normalization logic below.
1588+
_unit_lower = unit.lower()
1589+
if unit == 'B' or _unit_lower in ('byte', 'bytes'):
1590+
return Byte(float(val))
1591+
if unit == 'b' or _unit_lower in ('bit', 'bits'):
1592+
return Bit(float(val))
1593+
15861594
# Normalise: strip trailing b/B and append 'B' so we always
15871595
# work with byte-family units regardless of what was supplied.
15881596
unit = unit.rstrip('Bb')

docsite/source/_static/.gitkeep

Whitespace-only changes.

docsite/source/instances.rst

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ bitmath objects have several instance attributes:
109109
110110
>>> b = bitmath.Byte(1337)
111111
>>> print(b.unit)
112-
Byte
112+
B
113113
114114
.. py:attribute:: BitMathInstance.unit_plural
115115
@@ -119,7 +119,7 @@ bitmath objects have several instance attributes:
119119
120120
>>> b = bitmath.Byte(1337)
121121
>>> print(b.unit_plural)
122-
Bytes
122+
B
123123
124124
.. py:attribute:: BitMathInstance.unit_singular
125125
@@ -130,7 +130,7 @@ bitmath objects have several instance attributes:
130130
131131
>>> b = bitmath.Byte(1337)
132132
>>> print(b.unit_singular)
133-
Byte
133+
B
134134
135135
136136
**Notes:**
@@ -197,7 +197,7 @@ classes. You can even ``to_THING()`` an instance into itself again:
197197
>>> six_TB = TB(6)
198198
>>> six_TB_in_bits = six_TB.to_Bit()
199199
>>> print(six_TB, six_TB_in_bits)
200-
6.0 TB 4.8e+13 Bit
200+
6.0 TB 4.8e+13 b
201201
202202
>>> six_TB == six_TB_in_bits
203203
True
@@ -252,16 +252,16 @@ even easier to read.
252252
... print("Rate: %s/second" % Bit(_rate))
253253
... time.sleep(1)
254254
255-
Rate: 100.0 Bit/sec
256-
Rate: 24000.0 Bit/sec
257-
Rate: 1024.0 Bit/sec
258-
Rate: 60151.0 Bit/sec
259-
Rate: 33.0 Bit/sec
260-
Rate: 9999.0 Bit/sec
261-
Rate: 9238742.0 Bit/sec
262-
Rate: 2.09895849555e+13 Bit/sec
263-
Rate: 934098021.0 Bit/sec
264-
Rate: 934894.0 Bit/sec
255+
Rate: 100.0 b/sec
256+
Rate: 24000.0 b/sec
257+
Rate: 1024.0 b/sec
258+
Rate: 60151.0 b/sec
259+
Rate: 33.0 b/sec
260+
Rate: 9999.0 b/sec
261+
Rate: 9238742.0 b/sec
262+
Rate: 2.09895849555e+13 b/sec
263+
Rate: 934098021.0 b/sec
264+
Rate: 934894.0 b/sec
265265
266266
And now using a custom formatting definition:
267267

@@ -271,11 +271,11 @@ And now using a custom formatting definition:
271271
... print(Bit(_rate).best_prefix().format("Rate: {value:.3f} {unit}/sec"))
272272
... time.sleep(1)
273273
274-
Rate: 12.500 Byte/sec
274+
Rate: 12.500 B/sec
275275
Rate: 2.930 KiB/sec
276-
Rate: 128.000 Byte/sec
276+
Rate: 128.000 B/sec
277277
Rate: 7.343 KiB/sec
278-
Rate: 4.125 Byte/sec
278+
Rate: 4.125 B/sec
279279
Rate: 1.221 KiB/sec
280280
Rate: 1.101 MiB/sec
281281
Rate: 2.386 TiB/sec
@@ -304,7 +304,7 @@ bitmath instances come with a verbose built-in string representation:
304304
305305
>>> leet_bits = Bit(1337)
306306
>>> print(leet_bits)
307-
1337.0 Bit
307+
1337.0 b
308308
309309
However, for instances which aren't whole numbers (as in ``MiB(1/3.0)
310310
== 0.333333333333 MiB``, etc), their representation can be undesirable.
@@ -535,7 +535,7 @@ classes. Under the covers these properties call ``to_THING``.
535535
536536
>>> six_TB = TB(6)
537537
>>> print(six_TB, six_TB.Bit)
538-
6.0 TB 4.8e+13 Bit
538+
6.0 TB 4.8e+13 b
539539
540540
>>> six_TB == six_TB.Bit
541541
True

docsite/source/module.rst

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ bitmath.getsize()
5656
5757
>>> import bitmath
5858
>>> print(bitmath.getsize('./bitmath/__init__.py', bestprefix=False))
59-
34159.0 Byte
59+
34159.0 B
6060
6161
Recall, the default for representation is with the best
6262
human-readable prefix. We can control the prefix system used by
@@ -208,7 +208,7 @@ bitmath.listdir()
208208
>>> print(discovered_files)
209209
[Byte(1337.0), Byte(13370.0)]
210210
>>> print(reduce(lambda x,y: x+y, discovered_files))
211-
14707.0 Byte
211+
14707.0 B
212212
>>> print(reduce(lambda x,y: x+y, discovered_files).best_prefix())
213213
14.3623046875 KiB
214214
>>> print(reduce(lambda x,y: x+y, discovered_files).best_prefix().format("{value:.3f} {unit}"))
@@ -721,9 +721,9 @@ bitmath.format()
721721

722722
None of the following will be pluralized, because that feature is turned off
723723

724-
One unit of 'Bit': 1.0 Bit
724+
One unit of 'Bit': 1.0 b
725725

726-
0 of a unit is typically said pluralized in US English: 0.0 Byte
726+
0 of a unit is typically said pluralized in US English: 0.0 B
727727

728728
several items of a unit will always be pluralized in normal US English
729729
speech: 42.0 kb
@@ -733,9 +733,9 @@ bitmath.format()
733733
Now, we'll use the bitmath.format() context manager
734734
to print the same test string, but with pluralization enabled.
735735

736-
One unit of 'Bit': 1.0 Bit
736+
One unit of 'Bit': 1.0 b
737737

738-
0 of a unit is typically said pluralized in US English: 0.0 Bytes
738+
0 of a unit is typically said pluralized in US English: 0.0 B
739739

740740
several items of a unit will always be pluralized in normal US English
741741
speech: 42.0 kbs
@@ -754,13 +754,13 @@ bitmath.format()
754754
755755
>>> import bitmath
756756
>>> print("Some instances: %s, %s" % (bitmath.KiB(1 / 3.0), bitmath.Bit(512)))
757-
Some instances: 0.333333333333 KiB, 512.0 Bit
757+
Some instances: 0.333333333333 KiB, 512.0 b
758758
>>> with bitmath.format("{value:e}-{unit}"):
759759
... print("Some instances: %s, %s" % (bitmath.KiB(1 / 3.0), bitmath.Bit(512)))
760760
...
761-
Some instances: 3.333333e-01-KiB, 5.120000e+02-Bit
761+
Some instances: 3.333333e-01-KiB, 5.120000e+02-b
762762
>>> print("Some instances: %s, %s" % (bitmath.KiB(1 / 3.0), bitmath.Bit(512)))
763-
Some instances: 0.333333333333 KiB, 512.0 Bit
763+
Some instances: 0.333333333333 KiB, 512.0 b
764764
765765
766766
.. versionadded:: 1.0.8
@@ -805,7 +805,7 @@ behavior.
805805
806806
>>> from bitmath import *
807807
>>> print(MiB(1337), kb(0.1234567), Byte(0))
808-
1337.0 MiB 0.1234567 kb 0.0 Byte
808+
1337.0 MiB 0.1234567 kb 0.0 B
809809
810810
We can make these instances print however we want to. Let's wrap
811811
each one in square brackets (``[``, ``]``), replace the separating

tests/test_context_manager.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def test_with_format(self):
4747
]
4848

4949
str_reps = [
50-
"101.00-Byte",
50+
"101.00-B",
5151
"202.00-KiB",
5252
"303.00-MB",
5353
"404.00-GiB",
@@ -68,7 +68,7 @@ def test_with_format(self):
6868

6969
def test_print_byte_plural(self):
7070
"""Byte(3.0) prints out units in plural form"""
71-
expected_result = "3Bytes"
71+
expected_result = "3B"
7272
fmt_str = "{value:.1g}{unit}"
7373
three_Bytes = bitmath.Byte(3.0)
7474

@@ -78,7 +78,7 @@ def test_print_byte_plural(self):
7878

7979
def test_print_byte_plural_fmt_in_mgr(self):
8080
"""Byte(3.0) prints out units in plural form, setting the fmt str in the mgr"""
81-
expected_result = "3Bytes"
81+
expected_result = "3B"
8282

8383
with bitmath.format(fmt_str="{value:.1g}{unit}", plural=True):
8484
three_Bytes = bitmath.Byte(3.0)

tests/test_context_manager_thread_safe.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,12 @@ def plural_worker(expect_plural):
9393
with bitmath.format(plural=expect_plural):
9494
barrier.wait()
9595
result = str(bitmath.Byte(3.0))
96-
if expect_plural and result != "3.0 Bytes":
96+
if expect_plural and result != "3.0 B":
9797
errors.put(AssertionError(
98-
"plural thread: expected '3.0 Bytes', got %r" % result))
99-
elif not expect_plural and result != "3.0 Byte":
98+
"plural thread: expected '3.0 B', got %r" % result))
99+
elif not expect_plural and result != "3.0 B":
100100
errors.put(AssertionError(
101-
"singular thread: expected '3.0 Byte', got %r" % result))
101+
"singular thread: expected '3.0 B', got %r" % result))
102102
except Exception as exc:
103103
errors.put(exc)
104104

tests/test_parse.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,32 @@ def test_parse_non_strict_github_issue_60(self):
299299
bitmath.parse_string('4.7M', strict=False, system=bitmath.SI),
300300
bitmath.MB(4.7))
301301

302+
def test_parse_non_strict_capital_B_is_Byte(self):
303+
"""parse_string strict=False: lone 'B' parses as Byte"""
304+
self.assertIs(type(bitmath.parse_string("1B", strict=False)), bitmath.Byte)
305+
self.assertEqual(bitmath.parse_string("1 B", strict=False), bitmath.Byte(1))
306+
307+
def test_parse_non_strict_lowercase_b_is_Bit(self):
308+
"""parse_string strict=False: lone 'b' parses as Bit"""
309+
self.assertIs(type(bitmath.parse_string("1b", strict=False)), bitmath.Bit)
310+
self.assertEqual(bitmath.parse_string("1 b", strict=False), bitmath.Bit(1))
311+
312+
def test_parse_non_strict_bit_word_forms(self):
313+
"""parse_string strict=False: bit/bits/Bit/Bits/BIT all parse as Bit"""
314+
expected = bitmath.Bit(42)
315+
for unit in ('bit', 'bits', 'Bit', 'Bits', 'BIT', 'BITS'):
316+
result = bitmath.parse_string(f"42 {unit}", strict=False)
317+
self.assertEqual(result, expected, msg=f"Failed for unit '{unit}'")
318+
self.assertIs(type(result), bitmath.Bit, msg=f"Wrong type for unit '{unit}'")
319+
320+
def test_parse_non_strict_byte_word_forms(self):
321+
"""parse_string strict=False: byte/bytes/Byte/Bytes/BYTE all parse as Byte"""
322+
expected = bitmath.Byte(42)
323+
for unit in ('byte', 'bytes', 'Byte', 'Bytes', 'BYTE', 'BYTES'):
324+
result = bitmath.parse_string(f"42 {unit}", strict=False)
325+
self.assertEqual(result, expected, msg=f"Failed for unit '{unit}'")
326+
self.assertIs(type(result), bitmath.Byte, msg=f"Wrong type for unit '{unit}'")
327+
302328
def test_parse_string_unsafe_deprecation_warning(self):
303329
"""parse_string_unsafe emits DeprecationWarning as of 2.0.0"""
304330
import warnings

tests/test_representation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def test_change_format_string(self):
142142

143143
def test_print_byte_singular(self):
144144
"""Byte(1.0) prints out units in singular form"""
145-
expected_result = "1Byte"
145+
expected_result = "1B"
146146
fmt_str = "{value:.2g}{unit}"
147147
one_Byte = bitmath.Byte(1.0)
148148
actual_result = one_Byte.format(fmt_str)

0 commit comments

Comments
 (0)