From 6c53f7d99738c294df645709939a23c9ef28af9d Mon Sep 17 00:00:00 2001 From: "Matthew J. Milner" Date: Thu, 6 Jun 2024 13:35:02 +0200 Subject: [PATCH] Add interfaces subpackage --- README.md | 38 +++++++++++++++++++++++------ pyproject.toml | 5 ++++ quanstants/interfaces/__init__.py | 0 quanstants/interfaces/astropy.py | 0 quanstants/interfaces/matplotlib.py | 0 quanstants/interfaces/pandas.py | 0 quanstants/interfaces/pint.py | 0 quanstants/interfaces/polars.py | 0 quanstants/unit.py | 12 ++++++--- 9 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 quanstants/interfaces/__init__.py create mode 100644 quanstants/interfaces/astropy.py create mode 100644 quanstants/interfaces/matplotlib.py create mode 100644 quanstants/interfaces/pandas.py create mode 100644 quanstants/interfaces/pint.py create mode 100644 quanstants/interfaces/polars.py diff --git a/README.md b/README.md index ff574c7..29d79f4 100644 --- a/README.md +++ b/README.md @@ -948,26 +948,50 @@ As far as possible, however, units are also made available under alternative nam For consistency, names of constants are written first and foremost in British/Irish/European English, but should also be available under the American English equivalents. -## Comparison to astropy and pint +## Comparison to other packages Both `astropy` (via its modules `constants` and `units`) and `pint` are excellent packages, but both had limitations that inspired the creation of `quanstants`. -Moreover, while they and various other packages each do some things very well and have some advanced functionality, all met only a subset of my (fairly basic) needs, so `quanstants` aims to take the best of each. +While they and various other packages each do some things very well and have some advanced functionality, all met only a subset of my (fairly basic) needs, so `quanstants` aims to take the best of each. +Moreover, I felt it was possible to have an API more user-friendly than the others available. -Most crucially, neither package makes the same opinionated decisions about number handling and rounding as `quanstants`: they do not store numbers as `Decimal` by default, or implement the more traditional rounding behaviour, or allow rounding to significant figures. +### astropy and pint -Specifically in comparison to `astropy`, the unit and constant selection is far broader than simply those useful for astronomers, and there is no reliance on `numpy`. +* Crucially, neither package makes the same opinionated decisions about number handling and rounding as `quanstants`: + * they do not store numbers as `Decimal` by default + * they do not implement the more traditional rounding behaviour + * they do not allow easy rounding to significant figures or to match the uncertainty +* Both treat radians and steradians as base units rather than as dimensionless units, making working with angles more complicated + +### astropy + +* The `quanstants` API is fairly similar to that of `astropy` +* The unit and constant selection is much broader than simply those useful for astronomers/astrophysicists +* `astropy` does not support conversion to and from relative temperatures on scales other than kelvin, whereas `quanstants` has full support for both relative and absolute temperatures +* `astropy` quantities do not have an associated uncertainty, whereas `quanstants` has full uncertainty support +* `astropy` places a lot more restrictions on which units can be prefixed +* `astropy` is 37 MB at the time of writing, and it depends on `numpy`, adding another 28 MB; `quanstants` has no hard dependency on `numpy` or any other large package +* As a result of the above, import time is significantly faster +* Also slightly faster in common operations + + +### pint + +* The `quanstants` API and codebase was written to be much simpler, more obvious, and more intuitive than that of `pint` +* The immutability of units and quantities, while not total, is much stronger in `quanstants` -- any function or operation that would change a `Quantity` returns a new `Quantity` +* Uncertainty support exists in `pint` but only via extension with a package, and it is often buggy; `quanstants` offers out-of-the-box native support for uncertainties that is reliable +* `pint` contains lots of units, but not many constants; `quanstants` contains significantly more constant values +* Significantly faster in common operations -Specifically in comparison to `pint`, quantities are immutable by design – any function or operation that would change a `Quantity` returns a new `Quantity`, and both units and quantities are hashable. -`quanstants` also contains significantly more constant values. ## What is not (yet) supported? The following are aimed for but are not yet implemented: * Complex numbers -* Logarithmic units * Adjustment of prefixes (either automatically or on request) so that e.g. 2000 kJ becomes 2 MJ +* Type hints to require quantities with a certain unit or dimension * `numpy` `ndarray`s of quantities +* `Arrow` arrays of quantities * Use in `polars` dataframes ## Why Decimal? diff --git a/pyproject.toml b/pyproject.toml index 70ebc87..e8ed668 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,6 +34,11 @@ dev-dependencies = [ "uncertainties>=3.1.7", "sigfig>=1.3.3", "twine>=5.0.0", + "pint>=0.23", + "polars>=0.20.31", + "pandas>=2.2.2", + "matplotlib>=3.9.0", + "astropy>=6.1.0", ] [tool.hatch.metadata] diff --git a/quanstants/interfaces/__init__.py b/quanstants/interfaces/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/quanstants/interfaces/astropy.py b/quanstants/interfaces/astropy.py new file mode 100644 index 0000000..e69de29 diff --git a/quanstants/interfaces/matplotlib.py b/quanstants/interfaces/matplotlib.py new file mode 100644 index 0000000..e69de29 diff --git a/quanstants/interfaces/pandas.py b/quanstants/interfaces/pandas.py new file mode 100644 index 0000000..e69de29 diff --git a/quanstants/interfaces/pint.py b/quanstants/interfaces/pint.py new file mode 100644 index 0000000..e69de29 diff --git a/quanstants/interfaces/polars.py b/quanstants/interfaces/polars.py new file mode 100644 index 0000000..e69de29 diff --git a/quanstants/unit.py b/quanstants/unit.py index d95a2aa..f825e4f 100755 --- a/quanstants/unit.py +++ b/quanstants/unit.py @@ -319,8 +319,9 @@ def canonical(self) -> Quantity: class UnitlessUnit(BaseUnit): """Special dimensionless units that are numerically equal to 1. - Derives from `BaseUnit` and acts similar in most ways, but in arithmetic and - equalities behaves like unity. + Acts similarly to a BaseUnit in some ways, but in arithmetic and equalities behaves + like unity. + Note that a unitless unit is not simply dimensionless, and not all dimensionless units are instances of `UnitlessUnit`. For example, the degree is defined as a dimensionless `DerivedUnit` defined in terms @@ -399,7 +400,12 @@ def _cancel_to_unit(self, force_drop_unitless: bool = False) -> Unit: return self def fully_cancel(self) -> Quantity: - return Quantity(1, unitless) + return unitless._value + + def base(self) -> Quantity: + #return Quantity(1, unitless) + # No need to create a new quantity object for this + return unitless._value # Instantiate the main UnitlessUnit instance which is the one typically used internally