pintext#

The core API depends on Pint alone.

Unit contexts#

class pintext.UnitGenerator(units)[source]#

A callable object which returns units objects. Stored units can be contextually overridden using the override() method.

Parameters:

units (Unit | Callable[[], Unit]) – Stored units or generator.

Examples

>>> ugen = UnitGenerator(ureg.m)
>>> ugen()
<Unit('meter')>

Stored units can be modified, including temporarily:

>>> with ugen.override(ureg.km):
...     ugen()
<Unit('kilometer')>
>>> ugen()
<Unit('meter')>

See also

UnitContext

override(units)[source]#

Temporarily override the value of units. The initial value of units is restored upon leaving context.

Parameters:

units (Unit | Callable[[], Unit] | str) – Temporary replacement for units. String values are interpreted based on the unit registry of currently stored units.

Return type:

Generator[None]

Note

This context manager mutates the generator in-place and is therefore not thread-safe.

units: Unit | Callable[[], Unit]#

Stored units or generator.

class pintext.UnitContext(registry=<factory>, interpret_str=False, ureg=None, key_converter=<function identity>)[source]#

An overridable registry of UnitGenerator objects.

This class maintains a registry of UnitGenerator instances. Stored UnitGenerator objects can be conveniently overridden using the override() context manager.

Parameters:
  • registry (dict[Hashable, UnitGenerator | Unit | str]) –

    Unit generator registry. Keys can be any hashable type, but str or Enum are recommended. Defaults to an empty dictionary.

    Note

    The initialization sequence will make repeated calls to register() and will consequently apply the same key and value conversion rules.

  • interpret_str (bool) – If True, attempt string-to-units interpretation when specifying unit generators as str. Defaults to False.

  • ureg (UnitRegistry | None) – Unit registry used for string-to-units interpretation. If None, the default registry is used (see get_unit_registry()).

  • key_converter (Callable[[Hashable], Hashable]) – Converter used for keys. Defaults to a no-op.

deferred(key)[source]#

Return the UnitGenerator registered with a given key.

Parameters:

key (Hashable) – Key to the UnitGenerator to return. The key_converter is applied.

Return type:

UnitGenerator

Returns:

Unit generator.

get(key)[source]#

Evaluate UnitGenerator instance registered as key.

Parameters:

key (Hashable) – Key to the UnitGenerator to evaluate. The key_converter is applied.

Return type:

Unit

Returns:

Evaluated units.

get_all()[source]#

Evaluate all registered UnitGenerator instance.

Return type:

dict[Hashable, Unit]

Returns:

Evaluated units as a dictionary.

interpret_str: bool#

String-to-units interpretation switch.

key_converter: Callable[[Hashable], Hashable]#

Converter used for keys.

override(*args, **kwargs)[source]#

Temporarily override underlying unit generators. This method acts as a convenience proxy for UnitGenerator.override().

Override specifications can take multiple forms:

  • an arbitrary number of dictionaries can be passed as positional arguments;

  • key-value pairs may also be specified as keyword arguments.

Both approaches can be mixed.

Note

When using the keyword argument specification, passed values will systematically be strings. Consequently, either

  • registry keys must be strings;

  • or the key_converter must provide the conversion protocol for string-valued keys.

Return type:

Generator[None]

register(key, value)[source]#

Add or update an entry in the registry. Conversion rules are applied as follows:

  • key is applied the key_converter converter;

  • value is converted to a UnitGenerator.

In addition, if interpret_str is True, value can be specified as a string. In that case, it will be converted to a pint.Unit using the unit registry returned by get_unit_registry().

Parameters:
Return type:

None

registry: dict[Hashable, UnitGenerator | Unit | str]#

Unit generator registry.

update(d)[source]#

Update the registry with a dictionary.

Parameters:

d (dict) – Dictionary used to apply register() for each of its key-value pairs.

Return type:

None

ureg: UnitRegistry | None#

Unit registry used for string-to-units interpretation.

Unit registry#

pintext.get_unit_registry()[source]#

Get the default unit registry. By default, Pintext uses the application registry.

Return type:

UnitRegistry | ApplicationRegistry

Returns:

The registry currently used as a default by Pintext.

pintext.set_unit_registry(ureg)[source]#

Set the default unit registry. By default, Pintext uses the application registry.

Parameters:

ureg (UnitRegistry | ApplicationRegistry) – Unit registry.

Raises:

TypeError if ureg is not a pint.UnitRegistry.

Return type:

None

Converters#

pintext.ensure_units(maybe_value=NOTHING, *, default_units, convert=False)[source]#

Ensure that a value is wrapped in a Pint quantity container.

This converter can be used in two modes:

  • Immediate mode: Pass a value to convert it directly.

  • Deferred mode: Omit the value to get a converter function.

Parameters:
  • maybe_value (Any) – Value to ensure the wrapping of. If not supplied, this function returns a converter with the signature f(x: Any) -> Any that is effectively functools.partial(ensure_units, default_units=default_units, convert=convert).

  • default_units (Unit | Callable[[], Unit]) – Units to use to initialize the pint.Quantity if maybe_value is not a pint.Quantity. A callable can be passed; in this case, the applied units will be default_units().

  • convert (bool) – If True, maybe_value will also be converted to default_units if it is a pint.Quantity.

Return type:

Any

Returns:

Converted maybe_value if specified; otherwise, a converter function.

Raises:

pint.UndefinedUnitError – If maybe_value is a string Pint cannot parse.

Examples

  • Immediate mode. Convert a value directly:

    >>> ensure_units(100.0, default_units=ureg.m)
    <Quantity(100.0, 'meter')>
    

    By default, quantities with units are passed through unchanged:

    >>> ensure_units(100.0 * ureg.km, default_units=ureg.m)
    <Quantity(100.0, 'kilometer')>
    

    Set convert=True to force conversion to the default units:

    >>> ensure_units(100.0 * ureg.km, default_units=ureg.m, convert=True)
    <Quantity(100000.0, 'meter')>
    

    Strings are parsed by the default registry; those that carry no units are treated as unitless values:

    >>> ensure_units("2 m", default_units=ureg.km)
    <Quantity(2, 'meter')>
    >>> ensure_units("2", default_units=ureg.km)
    <Quantity(2, 'kilometer')>
    
  • Deferred mode: Create a converter function:

    >>> converter = ensure_units(default_units=ureg.km)
    >>> converter(5.0)
    <Quantity(5.0, 'kilometer')>
    >>> converter(100.0 * ureg.m)
    <Quantity(100.0, 'meter')>
    

    Deferred units are reevaluated on every call, which allows leveraging unit context overrides dynamically:

    >>> generator = UnitGenerator(ureg.m)
    >>> converter = ensure_units(default_units=generator)
    >>> converter(1.0)
    <Quantity(1.0, 'meter')>
    >>> with generator.override(ureg.km):
    ...     converter(1.0)
    <Quantity(1.0, 'kilometer')>
    
pintext.to_quantity(value, strict=False)[source]#

Attempts turning an object into a Pint quantity.

Values for which conversion fails are passed through, unless strict mode is active.

This converter is useful for loading data from serialized formats (JSON, YAML) or working with xarray DataArrays that carry units in a Pint-compatible format.

The following types are supported:

  • pint.Quantity: passed through unchanged.

  • dict (or, more generally, mappings): the magnitude (resp. units) must be supplied as the value, magnitude or m keys (resp. units, unit or u).

  • xarray.DataArray: the magnitude is the underlying data array (converted to a NumPy array) and units are read from the units attribute. If the units attribute is missing, the DataArray is returned unchanged. If the xarray dependency is not installed, conversion is skipped.

  • Other types are tentatively converted by Pint. This, in particular, parses unit-carrying strings and applies dimensionless units to unitless values.

Warning

  • This converter uses the global unit registry from func:~pintext.get_unit_registry.

  • Extra keys in dictionaries will raise a ValueError.

Parameters:
  • value (Any) – Object to attempt conversion on.

  • strict (bool) – If True, failed conversion raises a ValueError.

Raises:
  • ValueError – When converting a dictionary, if a magnitude or unit key is missing.

  • ValueError – When converting a dictionary, if unhandled keys are supplied.

  • ValueError – When conversion to a quantity fails and strict is True.

Return type:

Any

Examples

  • Converting dictionaries: Useful for loading from JSON or YAML files:

    >>> to_quantity({"value": 1.0, "units": "m"})
    <Quantity(1.0, 'meter')>
    >>> to_quantity({"magnitude": 2.5, "units": "km"})
    <Quantity(2.5, 'kilometer')>
    

    Shorter key names are also supported:

    >>> to_quantity({"m": 100.0, "u": "cm"})
    <Quantity(100.0, 'centimeter')>
    
  • Converting xarray DataArrays: Extracts data and units from DataArrays following CF conventions (requires xarray):

    >>> data = xr.DataArray([1.0, 2.0, 3.0], attrs={"units": "m"})
    >>> to_quantity(data)
    <Quantity([1. 2. 3.], 'meter')>
    

    DataArrays without units are passed through:

    >>> data = xr.DataArray([1.0, 2.0])
    >>> to_quantity(data)
    <xarray.DataArray (dim_0: 2)>...
    
  • Converting other types: unit-carrying strings are parsed, unitless values become dimensionless quantities:

    >>> to_quantity("2 m")
    <Quantity(2, 'meter')>
    >>> to_quantity(42.0)
    <Quantity(42.0, 'dimensionless')>
    

    Values Pint cannot interpret pass through, unless strict is True:

    >>> to_quantity("text")
    'text'
    >>> to_quantity("text", strict=True)
    Traceback (most recent call last):
        ...
    ValueError: Conversion of value to quantity failed (got 'text')
    

Utilities#

pintext.units_compatible(unit1, unit2)[source]#

Check if two units are compatible. Accounts for angle units.

Parameters:
  • unit1 (Unit) – First unit to check for compatibility.

  • unit2 (Unit) – Second unit to check for compatibility.

Return type:

bool

Returns:

True if unit1 and unit2 have the same dimensionality, False otherwise.

Examples

>>> units_compatible(ureg.m, ureg.km)
True
>>> units_compatible(ureg.m, ureg.s)
False

Angles are deliberately not considered compatible with dimensionless values, even though Pint converts between them:

>>> units_compatible(ureg.rad, ureg.dimensionless)
False
>>> units_compatible(ureg.sr, ureg.rad)
False
pintext.check_units(value, units, name=None)[source]#

Check that a value carries units compatible (in the sense of units_compatible()) with units.

This is the framework-agnostic unit check shared by the attrs and pydantic integrations.

Parameters:
  • value – Value to check. Expected to be a pint.Quantity.

  • units (Unit) – Units value must be compatible with.

  • name (str | None) – Name of the field being checked, used to build the error message. If None, a generic message is produced.

Raises:

UnitsError – If units are incompatible, or if a unitless value is provided.

Return type:

None

Examples

>>> check_units(1.0 * ureg.km, ureg.m)

An incompatible value raises:

>>> check_units(1.0 * ureg.s, ureg.m)
Traceback (most recent call last):
  ...
pintext.exceptions.UnitsError: Cannot convert from 'second' to 'meter': ...

Exceptions#

class pintext.UnitsError(units1, units2, dim1='', dim2='', extra_msg='')[source]#

Raised when encountering issues with units (can be raised even when DimensionalityError would not).