summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-10-26 18:05:42 +0000
committerGitHub <noreply@github.com>2022-10-26 18:05:42 +0000
commitcf1a80220dfc058bba4b127beb32a335a1f89248 (patch)
tree7fbd2929abaa0783b7bd2956c57a5ee3ec1b25f8
parent984923a90c5fefb69783d5d26ad215820ede0559 (diff)
parent5e3c937a4782c1fc55561e90c157eeb68211d203 (diff)
downloadpint-staging.tar.gz
Merge #1633staging
1633: Simplify registry subclassing r=hgrecco a=hgrecco - [x] Closes #1631 - [x] Executed ``pre-commit run --all-files`` with no errors - [x] The change is fully covered by automated unit tests - [x] Documented in docs/ as appropriate - [x] Added an entry to the CHANGES file Co-authored-by: Hernan <hernan.grecco@gmail.com> Co-authored-by: Hernan Grecco <hernan.grecco@gmail.com>
-rw-r--r--.github/workflows/ci.yml74
-rw-r--r--CHANGES2
-rw-r--r--docs/advanced_guides.rst1
-rw-r--r--docs/user/custom-registry-class.rst83
-rw-r--r--pint/testsuite/test_issues.py21
-rw-r--r--pint/util.py15
-rw-r--r--setup.cfg1
7 files changed, 182 insertions, 15 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e70fd13..8e44023 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -92,18 +92,8 @@ jobs:
strategy:
fail-fast: false
matrix:
- python-version: [3.8, 3.9, "3.10"]
+ python-version: [3.8, 3.9, "3.10", "3.11"]
numpy: [ "numpy>=1.19,<2.0.0" ]
- # uncertainties: [null, "uncertainties==3.1.6", "uncertainties>=3.1.6,<4.0.0"]
- # extras: [null]
- # include:
- # - python-version: 3.8 # Minimal versions
- # numpy: numpy==1.19.5
- # extras: matplotlib==2.2.5
- # - python-version: 3.8
- # numpy: "numpy"
- # uncertainties: "uncertainties"
- # extras: "sparse xarray netCDF4 dask[complete] graphviz babel==2.8"
runs-on: windows-latest
env:
@@ -159,6 +149,68 @@ jobs:
- name: Run tests
run: pytest ${env:TEST_OPTS}
+ test-macos:
+ strategy:
+ fail-fast: false
+ matrix:
+ python-version: [3.8, 3.9, "3.10", "3.11"]
+ numpy: [ "numpy>=1.19,<2.0.0" ]
+ runs-on: macos-latest
+
+ env:
+ TEST_OPTS: "-rfsxEX -s --cov=pint --cov-config=.coveragerc"
+
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 100
+
+ - name: Get tags
+ run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
+
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Get pip cache dir
+ id: pip-cache
+ run: echo "::set-output name=dir::$(pip cache dir)"
+
+ - name: Setup caching
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.pip-cache.outputs.dir }}
+ key: pip-${{ matrix.python-version }}
+ restore-keys: |
+ pip-${{ matrix.python-version }}
+
+ - name: Install numpy
+ if: ${{ matrix.numpy != null }}
+ run: pip install "${{matrix.numpy}}"
+
+ - name: Install dependencies
+ run: |
+ pip install pytest pytest-cov pytest-subtests
+ pip install .
+
+ - name: Run Tests
+ run: |
+ pytest $TEST_OPTS
+
+ - name: Coverage report
+ run: coverage report -m
+
+ - name: Coveralls Parallel
+ env:
+ COVERALLS_FLAG_NAME: ${{ matrix.test-number }}
+ COVERALLS_PARALLEL: true
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ COVERALLS_SERVICE_NAME: github
+ run: |
+ pip install coveralls
+ coveralls
+
coveralls:
needs: test-linux
runs-on: ubuntu-latest
diff --git a/CHANGES b/CHANGES
index 03932a4..04bfc8e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,7 +4,7 @@ Pint Changelog
0.21 (unreleased)
-----------------
-- Nothing changed yet.
+- Simplify registry subclassing and document it.
0.20 (2022-10-25)
diff --git a/docs/advanced_guides.rst b/docs/advanced_guides.rst
index cc2c495..580ddb7 100644
--- a/docs/advanced_guides.rst
+++ b/docs/advanced_guides.rst
@@ -12,3 +12,4 @@ Advanced Guides
user/measurement
user/pitheorem
user/currencies
+ user/custom-registry-class
diff --git a/docs/user/custom-registry-class.rst b/docs/user/custom-registry-class.rst
new file mode 100644
index 0000000..31f3d76
--- /dev/null
+++ b/docs/user/custom-registry-class.rst
@@ -0,0 +1,83 @@
+.. _custom_registry_class:
+
+Custom registry class
+=====================
+
+Pay as you go
+-------------
+
+Pint registry functionality is divided into facets. The default
+UnitRegistry inherits from all of them, providing a full fledged
+and feature rich registry. However, in certain cases you might want
+to have a simpler and light registry. Just pick what you need
+and create your own.
+
+- FormattingRegistry: adds the capability to format quantities and units into string.
+- SystemRegistry: adds the capability to work with system of units.
+- GroupRegistry: adds the capability to group units.
+- MeasurementRegistry: adds the capability to handle measurements (quantities with uncertainties).
+- NumpyRegistry: adds the capability to interoperate with NumPy.
+- DaskRegistry: adds the capability to interoperate with Dask.
+- ContextRegistry: the capability to contexts: predefined conversions
+ between incompatible dimensions.
+- NonMultiplicativeRegistry: adds the capability to handle nonmultiplicative units (offset, logarithmic).
+- PlainRegistry: base implementation for registry, units and quantities.
+
+The only required one is `PlainRegistry`, the rest are completely
+optional.
+
+For example:
+
+.. doctest::
+
+ >>> import pint
+ >>> class MyRegistry(pint.facets.NonMultiplicativeRegistry, pint.facets.PlainRegistry):
+ ... pass
+
+
+Subclassing
+-----------
+
+If you want to add the default registry class some specific functionality,
+you can subclass it:
+
+.. doctest::
+
+ >>> import pint
+ >>> class MyRegistry(pint.UnitRegistry):
+ ...
+ ... def my_specific_function(self):
+ ... """Do something
+ ... """
+
+
+If you want to create your own Quantity class, you must tell
+your registry about it:
+
+.. doctest::
+
+ >>> import pint
+ >>> class MyQuantity:
+ ...
+ ... # Notice that subclassing pint.Quantity
+ ... # is not necessary.
+ ... # Pint will inspect the Registry class and create
+ ... # a Quantity class that contains all the
+ ... # required parents.
+ ...
+ ... def to_my_desired_format(self):
+ ... """Do something else
+ ... """
+ >>>
+ >>> class MyRegistry(pint.UnitRegistry):
+ ...
+ ... _quantity_class = MyQuantity
+ ...
+ ... # The same you can be done with
+ ... # _unit_class
+ ... # _measurement_class
+
+
+While these examples demonstrate how to add functionality to the default
+registry class, you can actually subclass just the PlainRegistry or any
+combination of facets.
diff --git a/pint/testsuite/test_issues.py b/pint/testsuite/test_issues.py
index 80e2ebb..a07e850 100644
--- a/pint/testsuite/test_issues.py
+++ b/pint/testsuite/test_issues.py
@@ -1014,3 +1014,24 @@ def test_backcompat_speed_velocity(func_registry):
get = func_registry.get_dimensionality
assert get("[velocity]") == UnitsContainer({"[length]": 1, "[time]": -1})
assert get("[speed]") == UnitsContainer({"[length]": 1, "[time]": -1})
+
+
+def test_issue1631():
+ import pint
+
+ # Test registry subclassing
+ class MyRegistry(pint.UnitRegistry):
+ pass
+
+ assert MyRegistry.Quantity is pint.UnitRegistry.Quantity
+ assert MyRegistry.Unit is pint.UnitRegistry.Unit
+
+ ureg = MyRegistry()
+
+ u = ureg.meter
+ assert isinstance(u, ureg.Unit)
+ assert isinstance(u, pint.Unit)
+
+ q = 2 * ureg.meter
+ assert isinstance(q, ureg.Quantity)
+ assert isinstance(q, pint.Quantity)
diff --git a/pint/util.py b/pint/util.py
index eba747e..3d00175 100644
--- a/pint/util.py
+++ b/pint/util.py
@@ -10,6 +10,7 @@
from __future__ import annotations
+import functools
import inspect
import logging
import math
@@ -1021,6 +1022,13 @@ def sized(y) -> bool:
return True
+@functools.lru_cache(
+ maxsize=None
+) # TODO: replace with cache when Python 3.8 is dropped.
+def _build_type(class_name: str, bases):
+ return type(class_name, bases, dict())
+
+
def build_dependent_class(registry_class, class_name: str, attribute_name: str) -> Type:
"""Creates a class specifically for the given registry that
subclass all the classes named by the registry bases in a
@@ -1036,9 +1044,10 @@ def build_dependent_class(registry_class, class_name: str, attribute_name: str)
for base in inspect.getmro(registry_class)
if attribute_name in base.__dict__
)
- bases = dict.fromkeys(bases, None)
- newcls = type(class_name, tuple(bases.keys()), dict())
- return newcls
+ bases = tuple(dict.fromkeys(bases, None).keys())
+ if len(bases) == 1 and bases[0].__name__ == class_name:
+ return bases[0]
+ return _build_type(class_name, bases)
def create_class_with_registry(registry, base_class) -> Type:
diff --git a/setup.cfg b/setup.cfg
index cfa031f..9ce8b48 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -75,3 +75,4 @@ line_length=88
[zest.releaser]
python-file-with-version = version.py
+create-wheel = yes