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
2 changes: 1 addition & 1 deletion .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 ""
Expand Down
34 changes: 3 additions & 31 deletions bitmath/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# SPDX-License-Identifier: MIT
# The MIT License (MIT)
#
# Copyright © 2014-2016 Tim Case <timbielawa@gmail.com>
# Copyright © 2014-2026 Tim Case <bitmath@lnx.cx>
# See GitHub Contributors Graph for more information
#
# Permission is hereby granted, free of charge, to any person
Expand All @@ -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:
Expand Down Expand Up @@ -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:

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down
9 changes: 5 additions & 4 deletions docsite/source/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down
18 changes: 5 additions & 13 deletions docsite/source/module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -714,16 +714,10 @@ This section describes all of the `context managers
<https://docs.python.org/3/reference/datamodel.html#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
<instances_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::

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
51 changes: 51 additions & 0 deletions docsite/source/real_life_examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <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
********************************************

Expand Down
Loading