Skip to content

Commit

Permalink
Merge branch 'master' into codata_2022_update
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewgsavage authored Dec 15, 2024
2 parents 736ee66 + 2bdf58c commit 6e45879
Show file tree
Hide file tree
Showing 14 changed files with 179 additions and 62 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
numpy: [null, "numpy>=1.23,<2.0.0", "numpy>=2.0.0rc1"]
uncertainties: [null, "uncertainties==3.1.6", "uncertainties>=3.1.6,<4.0.0"]
extras: [null]
Expand Down
28 changes: 24 additions & 4 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,20 +1,40 @@
Pint Changelog
==============

0.25 (unreleased)
-----------------
0.25.0 (unreleased)
-------------------

- Add docs to the functions in ``pint.testing`` (PR #2070)
- Fix round function returning float instead of int (#2081)
- Update constants to CODATA 2022 recommended values. (#2049)


0.24.4 (2024-11-07)
-------------------

- add error for prefixed non multi units (#1998)
- build: typing_extensions version
- build: switch from appdirs to platformdirs
- fix GenericPlainRegistry getattr type (#2045)
- Replace references to the deprecated `UnitRegistry.default_format` (#2058)
- fix: upgrade to flexparser>=0.4, exceptions are no longer dataclasses.
(required for Python 3.13)


0.24.2 (2024-07-28)
-------------------

- Fix the default behaviour for pint-convert (cli) for importing uncertainties package (PR #2032, Issue #2016)
- Added mu and mc as alternatives for SI micro prefix
- Added ℓ as alternative for liter
- Support permille units and `‰` symbol (PR #2033, Issue #1963)
- Switch from appdirs to platformdirs.
- Fixes issues related to GenericPlainRegistry.__getattr__ type (PR #2038, Issues #1946 and #1804)
- Update constants to CODATA 2022 recommended values.
- Removed deprecated references in documentation and tests (PR #2058, Issue #2057)


0.24.1 (2024-06-24)
-----------------
-------------------

- Fix custom formatter needing the registry object. (PR #2011)
- Support python 3.9 following difficulties installing with NumPy 2. (PR #2019)
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"sphinx_design",
]


# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

Expand Down
2 changes: 1 addition & 1 deletion docs/ecosystem.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Pint integrations:


Packages using pint:
------------------
--------------------

- `fluids <https://github.com/CalebBell/fluids>`_ Practical fluid dynamics calculations
- `ht <https://github.com/CalebBell/ht/>`_ Practical heat transfer calculations
Expand Down
4 changes: 2 additions & 2 deletions docs/getting/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ Additionally, you can specify a default format specification:
>>> accel = 1.3 * ureg.parse_units('meter/second**2')
>>> 'The acceleration is {}'.format(accel)
'The acceleration is 1.3 meter / second ** 2'
>>> ureg.default_format = 'P'
>>> ureg.formatter.default_format = 'P'
>>> 'The acceleration is {}'.format(accel)
'The acceleration is 1.3 meter/second²'

Expand Down Expand Up @@ -446,7 +446,7 @@ and by doing that, string formatting is now localized:

.. doctest::

>>> ureg.default_format = 'P'
>>> ureg.formatter.default_format = 'P'
>>> accel = 1.3 * ureg.parse_units('meter/second**2')
>>> str(accel)
'1,3 mètres par seconde²'
Expand Down
2 changes: 1 addition & 1 deletion docs/user/nonmult.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ For example, to convert from celsius to fahrenheit:

>>> from pint import UnitRegistry
>>> ureg = UnitRegistry()
>>> ureg.default_format = '.3f'
>>> ureg.formatter.default_format = '.3f'
>>> Q_ = ureg.Quantity
>>> home = Q_(25.4, ureg.degC)
>>> print(home.to('degF'))
Expand Down
9 changes: 6 additions & 3 deletions pint/delegates/txt_defparser/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@

from __future__ import annotations

from dataclasses import dataclass, field
from dataclasses import dataclass

import flexparser as fp

from ... import errors
from ..base_defparser import ParserConfig


@dataclass(frozen=True)
class DefinitionSyntaxError(errors.DefinitionSyntaxError, fp.ParsingError):
"""A syntax error was found in a definition. Combines:
Expand All @@ -30,7 +29,11 @@ class DefinitionSyntaxError(errors.DefinitionSyntaxError, fp.ParsingError):
and an extra location attribute in which the filename or reseource is stored.
"""

location: str = field(init=False, default="")
msg: str

def __init__(self, msg: str, location: str = ""):
self.msg = msg
self.location = location

def __str__(self) -> str:
msg = (
Expand Down
98 changes: 65 additions & 33 deletions pint/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from __future__ import annotations

import typing as ty
from dataclasses import dataclass, fields

OFFSET_ERROR_DOCS_HTML = "https://pint.readthedocs.io/en/stable/user/nonmult.html"
LOG_ERROR_DOCS_HTML = "https://pint.readthedocs.io/en/stable/user/log_units.html"
Expand Down Expand Up @@ -81,82 +80,87 @@ def def_err(self, msg: str):
return DefinitionError(self.name, self.__class__, msg)


@dataclass(frozen=False)
class PintError(Exception):
"""Base exception for all Pint errors."""


@dataclass(frozen=False)
class DefinitionError(ValueError, PintError):
"""Raised when a definition is not properly constructed."""

name: str
definition_type: type
msg: str

def __init__(self, name: str, definition_type: type, msg: str):
self.name = name
self.definition_type = definition_type
self.msg = msg

def __str__(self):
msg = f"Cannot define '{self.name}' ({self.definition_type}): {self.msg}"
return msg

def __reduce__(self):
return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
return self.__class__, (self.name, self.definition_type, self.msg)


@dataclass(frozen=False)
class DefinitionSyntaxError(ValueError, PintError):
"""Raised when a textual definition has a syntax error."""

msg: str

def __init__(self, msg: str):
self.msg = msg

def __str__(self):
return self.msg

def __reduce__(self):
return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
return self.__class__, (self.msg,)


@dataclass(frozen=False)
class RedefinitionError(ValueError, PintError):
"""Raised when a unit or prefix is redefined."""

name: str
definition_type: type

def __init__(self, name: str, definition_type: type):
self.name = name
self.definition_type = definition_type

def __str__(self):
msg = f"Cannot redefine '{self.name}' ({self.definition_type})"
return msg

def __reduce__(self):
return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
return self.__class__, (self.name, self.definition_type)


@dataclass(frozen=False)
class UndefinedUnitError(AttributeError, PintError):
"""Raised when the units are not defined in the unit registry."""

unit_names: str | tuple[str, ...]
unit_names: tuple[str, ...]

def __init__(self, unit_names: str | ty.Iterable[str]):
if isinstance(unit_names, str):
self.unit_names = (unit_names,)
else:
self.unit_names = tuple(unit_names)

def __str__(self):
if isinstance(self.unit_names, str):
return f"'{self.unit_names}' is not defined in the unit registry"
if (
isinstance(self.unit_names, (tuple, list, set))
and len(self.unit_names) == 1
):
if len(self.unit_names) == 1:
return f"'{tuple(self.unit_names)[0]}' is not defined in the unit registry"
return f"{tuple(self.unit_names)} are not defined in the unit registry"

def __reduce__(self):
return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
return self.__class__, (self.unit_names,)


@dataclass(frozen=False)
class PintTypeError(TypeError, PintError):
def __reduce__(self):
return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
pass


@dataclass(frozen=False)
class DimensionalityError(PintTypeError):
"""Raised when trying to convert between incompatible units."""

Expand All @@ -166,6 +170,20 @@ class DimensionalityError(PintTypeError):
dim2: str = ""
extra_msg: str = ""

def __init__(
self,
units1: ty.Any,
units2: ty.Any,
dim1: str = "",
dim2: str = "",
extra_msg: str = "",
) -> None:
self.units1 = units1
self.units2 = units2
self.dim1 = dim1
self.dim2 = dim2
self.extra_msg = extra_msg

def __str__(self):
if self.dim1 or self.dim2:
dim1 = f" ({self.dim1})"
Expand All @@ -180,16 +198,25 @@ def __str__(self):
)

def __reduce__(self):
return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
return self.__class__, (
self.units1,
self.units2,
self.dim1,
self.dim2,
self.extra_msg,
)


@dataclass(frozen=False)
class OffsetUnitCalculusError(PintTypeError):
"""Raised on ambiguous operations with offset units."""

units1: ty.Any
units2: ty.Optional[ty.Any] = None

def __init__(self, units1: ty.Any, units2: ty.Optional[ty.Any] = None) -> None:
self.units1 = units1
self.units2 = units2

def yield_units(self):
yield self.units1
if self.units2:
Expand All @@ -205,16 +232,19 @@ def __str__(self):
)

def __reduce__(self):
return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
return self.__class__, (self.units1, self.units2)


@dataclass(frozen=False)
class LogarithmicUnitCalculusError(PintTypeError):
"""Raised on inappropriate operations with logarithmic units."""

units1: ty.Any
units2: ty.Optional[ty.Any] = None

def __init__(self, units1: ty.Any, units2: ty.Optional[ty.Any] = None) -> None:
self.units1 = units1
self.units2 = units2

def yield_units(self):
yield self.units1
if self.units2:
Expand All @@ -230,26 +260,28 @@ def __str__(self):
)

def __reduce__(self):
return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
return self.__class__, (self.units1, self.units2)


@dataclass(frozen=False)
class UnitStrippedWarning(UserWarning, PintError):
msg: str

def __init__(self, msg: str):
self.msg = msg

def __reduce__(self):
return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
return self.__class__, (self.msg,)


@dataclass(frozen=False)
class UnexpectedScaleInContainer(Exception):
def __reduce__(self):
return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
pass


@dataclass(frozen=False)
class UndefinedBehavior(UserWarning, PintError):
msg: str

def __init__(self, msg: str):
self.msg = msg

def __reduce__(self):
return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
return self.__class__, (self.msg,)
12 changes: 6 additions & 6 deletions pint/facets/plain/quantity.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""
pint.facets.plain.quantity
~~~~~~~~~~~~~~~~~~~~~~~~~
pint.facets.plain.quantity
~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: 2022 by Pint Authors, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
:copyright: 2022 by Pint Authors, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""

from __future__ import annotations
Expand Down Expand Up @@ -1288,8 +1288,8 @@ def __rpow__(self, other) -> PlainQuantity[MagnitudeT]:
def __abs__(self) -> PlainQuantity[MagnitudeT]:
return self.__class__(abs(self._magnitude), self._units)

def __round__(self, ndigits: int | None = 0) -> PlainQuantity[MagnitudeT]:
return self.__class__(round(self._magnitude, ndigits=ndigits), self._units)
def __round__(self, ndigits: int | None = None) -> PlainQuantity[int]:
return self.__class__(round(self._magnitude, ndigits), self._units)

def __pos__(self) -> PlainQuantity[MagnitudeT]:
return self.__class__(operator.pos(self._magnitude), self._units)
Expand Down
Loading

0 comments on commit 6e45879

Please sign in to comment.