diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index be097ae..e080e7a 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -35,7 +35,7 @@ jobs: - name: Pre-Tests code smell validation run: | - pycodestyle -v --ignore=E501,E722 bitmath/__init__.py tests/ + pycodestyle -v --ignore=E501 bitmath/__init__.py tests/ flake8 --select=F bitmath/__init__.py tests/ - name: Run Unit Tests diff --git a/Makefile b/Makefile index e505b78..40a4352 100644 --- a/Makefile +++ b/Makefile @@ -207,7 +207,7 @@ ci-pycodestyle: @echo "#############################################" @echo "# Running PEP8 Compliance Tests in virtualenv" @echo "#############################################" - . $(NAME)env3/bin/activate && pycodestyle -v --ignore=E501,E722 bitmath/__init__.py tests/*.py + . $(NAME)env3/bin/activate && pycodestyle -v --ignore=E501 bitmath/__init__.py tests/*.py ci-flake8: @echo "" diff --git a/bitmath/__init__.py b/bitmath/__init__.py index b36161e..e69c4a5 100644 --- a/bitmath/__init__.py +++ b/bitmath/__init__.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT # The MIT License (MIT) # -# Copyright © 2014-2016 Tim Case +# Copyright © 2014-2026 Tim Case # See GitHub Contributors Graph for more information # # Permission is hereby granted, free of charge, to any person @@ -24,7 +24,7 @@ # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -# pylint: disable=bad-continuation,missing-docstring,invalid-name,line-too-long +# pylint: disable=line-too-long """Reference material: The bitmath homepage is located at: @@ -785,17 +785,6 @@ def __ge__(self, other): # Reference: https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types - """These methods are called to implement the binary arithmetic -operations (+, -, *, //, %, divmod(), pow(), **, <<, >>, &, ^, |). For -instance, to evaluate the expression x + y, where x is an instance of -a class that has an __add__() method, x.__add__(y) is called. The -__divmod__() method should be the equivalent to using __floordiv__() -and __mod__(); it should not be related to __truediv__() (described -below). Note that __pow__() should be defined to accept an optional -third argument if the ternary version of the built-in pow() function -is to be supported.object.__complex__(self) -""" - def __add__(self, other): """Supported operations with result types: @@ -895,20 +884,6 @@ def __divmod__(self, other): ################################################################## - """These methods are called to implement the binary arithmetic -operations (+, -, *, /, %, divmod(), pow(), **, <<, >>, &, ^, |) with -reflected (swapped) operands. These functions are only called if the -left operand does not support the corresponding operation and the -operands are of different types. [2] For instance, to evaluate the -expression x - y, where y is an instance of a class that has an -__rsub__() method, y.__rsub__(x) is called if x.__sub__(y) returns -NotImplemented. - -These are the add/sub/mul/div methods for syntax where a number type -is given for the LTYPE and a bitmath object is given for the -RTYPE. E.g., 3 * MiB(3), or 10 / GB(42) -""" - def __radd__(self, other): # Special case: 0 + bm = bm (identity element, enables built-in sum()) if other == 0: @@ -1663,10 +1638,7 @@ def parse_string(s: str | numbers.Number, system: int = NIST, strict: bool = Tru val = float(val) except ValueError: raise - try: - return unit_class(val) - except: # pragma: no cover - raise ValueError(f"Can't parse string {s} into a bitmath object") + return unit_class(val) else: # strict=False path (formerly parse_string_unsafe) diff --git a/docsite/source/contributing.rst b/docsite/source/contributing.rst index 54815c4..92cf61a 100644 --- a/docsite/source/contributing.rst +++ b/docsite/source/contributing.rst @@ -43,12 +43,13 @@ Two static analysis checks run on every pull request as part of the GitHub Actions CI workflow, and locally via ``make ci``: * ``pycodestyle`` — checks code style, with **E501** (line too long) - and **E722** (bare ``except``) ignored. + ignored. * ``flake8 --select=F`` — runs pyflakes error checks only (undefined names, unused imports, etc.). Style checks are disabled. -A PR cannot be merged until both pass. Run ``make ci`` locally to -check before submitting. +A PR cannot be merged until both pass. If you want to save time you +can run ``make ci`` locally to check before submitting and waiting on +the GitHub runners to report back. .. _contributing_commit_messages: @@ -102,7 +103,7 @@ This means the minimum supported version tracks the oldest Python still included in a supported EPEL target: * **RHEL 10 / EPEL 10** — Python 3.12 -* **RHEL 9 / EPEL 9** — Python 3.9, 3.11 +* **RHEL 9 / EPEL 9** — Python 3.9, 3.10, 3.11 The CI matrix tests all versions in this range. When a RHEL major release reaches end-of-life and is dropped from EPEL, the corresponding diff --git a/docsite/source/module.rst b/docsite/source/module.rst index 9a0aa04..f0dbbb4 100644 --- a/docsite/source/module.rst +++ b/docsite/source/module.rst @@ -714,16 +714,10 @@ This section describes all of the `context managers `_ provided by the bitmath class. -.. warning:: - - It is a known limitation that the bitmath context managers are - **not thread-safe**. You may get unexpected results or errors using - these in a threaded environment. - - The suggested workaround is to apply formatting to each object - instance directly. See the instance :ref:`format - ` method docs for additional reference. +.. note:: + Context manager settings are thread safe. Concurrent contexts in + different threads do not interfere with each other. .. note:: @@ -777,8 +771,6 @@ bitmath.format() unit. - .. note:: The ``bestprefix`` parameter is not yet implemented! - Let's look at an example of toggling pluralization on and off. First we'll look over a demonstration script (below), and then we'll review the output. @@ -865,13 +857,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 b + Some instances: 0.3333333333333333 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-b >>> print("Some instances: %s, %s" % (bitmath.KiB(1 / 3.0), bitmath.Bit(512))) - Some instances: 0.333333333333 KiB, 512.0 b + Some instances: 0.3333333333333333 KiB, 512.0 b .. versionadded:: 1.0.8 diff --git a/docsite/source/real_life_examples.rst b/docsite/source/real_life_examples.rst index 4966859..3b39641 100644 --- a/docsite/source/real_life_examples.rst +++ b/docsite/source/real_life_examples.rst @@ -85,6 +85,57 @@ The result on line **4** tells tells us that we could fit **256** average-quality songs on our iPod. +Using Real Device Capacity +========================== + +Rather than hard-coding a device size, we can query the actual free +space on any mounted filesystem with :func:`bitmath.query_capacity` +and feed that directly into the same calculation. + +:func:`bitmath.query_capacity` returns a :class:`Capacity` named +tuple with ``total``, ``used``, and ``free`` fields. By default +(``bestprefix=True``) each field is already normalized to a +human-readable prefix (e.g. ``GiB``). Pass ``bestprefix=False`` to +get raw :class:`bitmath.Byte` instances instead. It requires no +elevated privileges and works cross-platform. + +.. code-block:: python + + >>> import bitmath + >>> cap = bitmath.query_capacity("/") + >>> print(cap.free) + 93.08 GiB + +Now we can ask: *how many 4.7 GB DVD images fit in that free space?* + +.. code-block:: python + + >>> dvd = bitmath.GB(4.7) + >>> count, remainder = divmod(cap.free, dvd) + >>> print(int(count), "DVDs,", remainder.best_prefix(), "left over") + 19 DVDs, 3.262 GiB left over + +Floor division (``//``) and modulo (``%``) work the same way if you +only need one value: + +.. code-block:: python + + >>> print(int(cap.free // dvd), "DVDs fit") + 19 DVDs fit + >>> print((cap.free % dvd).best_prefix(), "remaining") + 3.262 GiB remaining + +.. seealso:: + + :ref:`Capacity Math ` + Details on floor division, modulo, and ``divmod`` for bitmath + objects. + + :func:`bitmath.query_capacity` + Full reference for the ``Capacity`` named tuple and + cross-platform behaviour. + + Printing Human-Readable File Sizes in Python ********************************************