Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions NEWS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ Breaking Changes
``setup.py`` and ``setup.py.in`` are gone. Installation is
``pip install bitmath``. Source builds use ``python -m build``.

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


Library Improvements
====================
Expand Down
12 changes: 10 additions & 2 deletions bitmath/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1022,7 +1022,7 @@ def __abs__(self):
class Byte(Bitmath):
"""Byte based types fundamentally operate on self._bit_value"""
def _setup(self):
return (2, 0, 'Byte', 'Bytes')
return (2, 0, 'B', 'B')

######################################################################
# NIST Prefixes for Byte based types
Expand Down Expand Up @@ -1167,7 +1167,7 @@ def _set_prefix_value(self):
self.prefix_value = self._to_prefix_value(self._bit_value)

def _setup(self):
return (2, 0, 'Bit', 'Bits')
return (2, 0, 'b', 'b')

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

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

# Explicit base-unit and word-form checks: handle B, b, bit(s),
# byte(s) before the prefix-normalization logic below.
_unit_lower = unit.lower()
if unit == 'B' or _unit_lower in ('byte', 'bytes'):
return Byte(float(val))
if unit == 'b' or _unit_lower in ('bit', 'bits'):
return Bit(float(val))

# Normalise: strip trailing b/B and append 'B' so we always
# work with byte-family units regardless of what was supplied.
unit = unit.rstrip('Bb')
Expand Down
Empty file added docsite/source/_static/.gitkeep
Empty file.
38 changes: 19 additions & 19 deletions docsite/source/instances.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ bitmath objects have several instance attributes:

>>> b = bitmath.Byte(1337)
>>> print(b.unit)
Byte
B

.. py:attribute:: BitMathInstance.unit_plural

Expand All @@ -119,7 +119,7 @@ bitmath objects have several instance attributes:

>>> b = bitmath.Byte(1337)
>>> print(b.unit_plural)
Bytes
B

.. py:attribute:: BitMathInstance.unit_singular

Expand All @@ -130,7 +130,7 @@ bitmath objects have several instance attributes:

>>> b = bitmath.Byte(1337)
>>> print(b.unit_singular)
Byte
B


**Notes:**
Expand Down Expand Up @@ -197,7 +197,7 @@ classes. You can even ``to_THING()`` an instance into itself again:
>>> six_TB = TB(6)
>>> six_TB_in_bits = six_TB.to_Bit()
>>> print(six_TB, six_TB_in_bits)
6.0 TB 4.8e+13 Bit
6.0 TB 4.8e+13 b

>>> six_TB == six_TB_in_bits
True
Expand Down Expand Up @@ -252,16 +252,16 @@ even easier to read.
... print("Rate: %s/second" % Bit(_rate))
... time.sleep(1)

Rate: 100.0 Bit/sec
Rate: 24000.0 Bit/sec
Rate: 1024.0 Bit/sec
Rate: 60151.0 Bit/sec
Rate: 33.0 Bit/sec
Rate: 9999.0 Bit/sec
Rate: 9238742.0 Bit/sec
Rate: 2.09895849555e+13 Bit/sec
Rate: 934098021.0 Bit/sec
Rate: 934894.0 Bit/sec
Rate: 100.0 b/sec
Rate: 24000.0 b/sec
Rate: 1024.0 b/sec
Rate: 60151.0 b/sec
Rate: 33.0 b/sec
Rate: 9999.0 b/sec
Rate: 9238742.0 b/sec
Rate: 2.09895849555e+13 b/sec
Rate: 934098021.0 b/sec
Rate: 934894.0 b/sec

And now using a custom formatting definition:

Expand All @@ -271,11 +271,11 @@ And now using a custom formatting definition:
... print(Bit(_rate).best_prefix().format("Rate: {value:.3f} {unit}/sec"))
... time.sleep(1)

Rate: 12.500 Byte/sec
Rate: 12.500 B/sec
Rate: 2.930 KiB/sec
Rate: 128.000 Byte/sec
Rate: 128.000 B/sec
Rate: 7.343 KiB/sec
Rate: 4.125 Byte/sec
Rate: 4.125 B/sec
Rate: 1.221 KiB/sec
Rate: 1.101 MiB/sec
Rate: 2.386 TiB/sec
Expand Down Expand Up @@ -304,7 +304,7 @@ bitmath instances come with a verbose built-in string representation:

>>> leet_bits = Bit(1337)
>>> print(leet_bits)
1337.0 Bit
1337.0 b

However, for instances which aren't whole numbers (as in ``MiB(1/3.0)
== 0.333333333333 MiB``, etc), their representation can be undesirable.
Expand Down Expand Up @@ -535,7 +535,7 @@ classes. Under the covers these properties call ``to_THING``.

>>> six_TB = TB(6)
>>> print(six_TB, six_TB.Bit)
6.0 TB 4.8e+13 Bit
6.0 TB 4.8e+13 b

>>> six_TB == six_TB.Bit
True
Expand Down
20 changes: 10 additions & 10 deletions docsite/source/module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ bitmath.getsize()

>>> import bitmath
>>> print(bitmath.getsize('./bitmath/__init__.py', bestprefix=False))
34159.0 Byte
34159.0 B

Recall, the default for representation is with the best
human-readable prefix. We can control the prefix system used by
Expand Down Expand Up @@ -208,7 +208,7 @@ bitmath.listdir()
>>> print(discovered_files)
[Byte(1337.0), Byte(13370.0)]
>>> print(reduce(lambda x,y: x+y, discovered_files))
14707.0 Byte
14707.0 B
>>> print(reduce(lambda x,y: x+y, discovered_files).best_prefix())
14.3623046875 KiB
>>> print(reduce(lambda x,y: x+y, discovered_files).best_prefix().format("{value:.3f} {unit}"))
Expand Down Expand Up @@ -721,9 +721,9 @@ bitmath.format()

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

One unit of 'Bit': 1.0 Bit
One unit of 'Bit': 1.0 b

0 of a unit is typically said pluralized in US English: 0.0 Byte
0 of a unit is typically said pluralized in US English: 0.0 B

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

One unit of 'Bit': 1.0 Bit
One unit of 'Bit': 1.0 b

0 of a unit is typically said pluralized in US English: 0.0 Bytes
0 of a unit is typically said pluralized in US English: 0.0 B

several items of a unit will always be pluralized in normal US English
speech: 42.0 kbs
Expand All @@ -754,13 +754,13 @@ bitmath.format()

>>> import bitmath
>>> print("Some instances: %s, %s" % (bitmath.KiB(1 / 3.0), bitmath.Bit(512)))
Some instances: 0.333333333333 KiB, 512.0 Bit
Some instances: 0.333333333333 KiB, 512.0 b
>>> with bitmath.format("{value:e}-{unit}"):
... print("Some instances: %s, %s" % (bitmath.KiB(1 / 3.0), bitmath.Bit(512)))
...
Some instances: 3.333333e-01-KiB, 5.120000e+02-Bit
Some instances: 3.333333e-01-KiB, 5.120000e+02-b
>>> print("Some instances: %s, %s" % (bitmath.KiB(1 / 3.0), bitmath.Bit(512)))
Some instances: 0.333333333333 KiB, 512.0 Bit
Some instances: 0.333333333333 KiB, 512.0 b


.. versionadded:: 1.0.8
Expand Down Expand Up @@ -805,7 +805,7 @@ behavior.

>>> from bitmath import *
>>> print(MiB(1337), kb(0.1234567), Byte(0))
1337.0 MiB 0.1234567 kb 0.0 Byte
1337.0 MiB 0.1234567 kb 0.0 B

We can make these instances print however we want to. Let's wrap
each one in square brackets (``[``, ``]``), replace the separating
Expand Down
6 changes: 3 additions & 3 deletions tests/test_context_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def test_with_format(self):
]

str_reps = [
"101.00-Byte",
"101.00-B",
"202.00-KiB",
"303.00-MB",
"404.00-GiB",
Expand All @@ -68,7 +68,7 @@ def test_with_format(self):

def test_print_byte_plural(self):
"""Byte(3.0) prints out units in plural form"""
expected_result = "3Bytes"
expected_result = "3B"
fmt_str = "{value:.1g}{unit}"
three_Bytes = bitmath.Byte(3.0)

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

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

with bitmath.format(fmt_str="{value:.1g}{unit}", plural=True):
three_Bytes = bitmath.Byte(3.0)
Expand Down
8 changes: 4 additions & 4 deletions tests/test_context_manager_thread_safe.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ def plural_worker(expect_plural):
with bitmath.format(plural=expect_plural):
barrier.wait()
result = str(bitmath.Byte(3.0))
if expect_plural and result != "3.0 Bytes":
if expect_plural and result != "3.0 B":
errors.put(AssertionError(
"plural thread: expected '3.0 Bytes', got %r" % result))
elif not expect_plural and result != "3.0 Byte":
"plural thread: expected '3.0 B', got %r" % result))
elif not expect_plural and result != "3.0 B":
errors.put(AssertionError(
"singular thread: expected '3.0 Byte', got %r" % result))
"singular thread: expected '3.0 B', got %r" % result))
except Exception as exc:
errors.put(exc)

Expand Down
26 changes: 26 additions & 0 deletions tests/test_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,32 @@ def test_parse_non_strict_github_issue_60(self):
bitmath.parse_string('4.7M', strict=False, system=bitmath.SI),
bitmath.MB(4.7))

def test_parse_non_strict_capital_B_is_Byte(self):
"""parse_string strict=False: lone 'B' parses as Byte"""
self.assertIs(type(bitmath.parse_string("1B", strict=False)), bitmath.Byte)
self.assertEqual(bitmath.parse_string("1 B", strict=False), bitmath.Byte(1))

def test_parse_non_strict_lowercase_b_is_Bit(self):
"""parse_string strict=False: lone 'b' parses as Bit"""
self.assertIs(type(bitmath.parse_string("1b", strict=False)), bitmath.Bit)
self.assertEqual(bitmath.parse_string("1 b", strict=False), bitmath.Bit(1))

def test_parse_non_strict_bit_word_forms(self):
"""parse_string strict=False: bit/bits/Bit/Bits/BIT all parse as Bit"""
expected = bitmath.Bit(42)
for unit in ('bit', 'bits', 'Bit', 'Bits', 'BIT', 'BITS'):
result = bitmath.parse_string(f"42 {unit}", strict=False)
self.assertEqual(result, expected, msg=f"Failed for unit '{unit}'")
self.assertIs(type(result), bitmath.Bit, msg=f"Wrong type for unit '{unit}'")

def test_parse_non_strict_byte_word_forms(self):
"""parse_string strict=False: byte/bytes/Byte/Bytes/BYTE all parse as Byte"""
expected = bitmath.Byte(42)
for unit in ('byte', 'bytes', 'Byte', 'Bytes', 'BYTE', 'BYTES'):
result = bitmath.parse_string(f"42 {unit}", strict=False)
self.assertEqual(result, expected, msg=f"Failed for unit '{unit}'")
self.assertIs(type(result), bitmath.Byte, msg=f"Wrong type for unit '{unit}'")

def test_parse_string_unsafe_deprecation_warning(self):
"""parse_string_unsafe emits DeprecationWarning as of 2.0.0"""
import warnings
Expand Down
2 changes: 1 addition & 1 deletion tests/test_representation.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def test_change_format_string(self):

def test_print_byte_singular(self):
"""Byte(1.0) prints out units in singular form"""
expected_result = "1Byte"
expected_result = "1B"
fmt_str = "{value:.2g}{unit}"
one_Byte = bitmath.Byte(1.0)
actual_result = one_Byte.format(fmt_str)
Expand Down
Loading