pintext.pydantic#

The pydantic integration (pydantic v2). Requires the pydantic extra:

python -m pip install "pintext[pydantic]"
class pintext.pydantic.Units(units=None, *, convert=False)[source]#

Pydantic annotation turning a field into a Pint quantity.

Use it as Annotated metadata:

radius: Annotated[pint.Quantity, Units(ureg.m)]

This is the spelling static type checkers understand. quantity() is a more concise equivalent, at the cost of being a function call in an annotation, which type checkers reject.

Parameters:
  • units (Unit | UnitGenerator | str | None) – Units attached to the field. A UnitGenerator (e.g. obtained from UnitContext.deferred()) defers unit evaluation to validation time, which makes unit contexts apply. Strings are interpreted using the registry returned by get_unit_registry(). If None, any quantity is accepted, no default units are applied and no compatibility check is performed.

  • convert (bool) – If True, quantities are converted to units instead of being passed through unchanged.

pintext.pydantic.quantity(units, *, convert=False)[source]#

Build an annotated type for a field holding a Pint quantity with declared units.

Values are interpreted as follows:

  • mappings and xarray DataArrays are first passed to to_quantity();

  • strings are parsed by ensure_units(), which means that those carrying no units are attached units;

  • unitless values are attached units;

  • quantities are checked for unit compatibility with check_units().

Parameters:
  • units (Unit | UnitGenerator | str) – Units attached to the field. A UnitGenerator (e.g. obtained from UnitContext.deferred()) defers unit evaluation to validation time, which makes unit contexts effective. Strings are interpreted using the registry returned by get_unit_registry().

  • convert (bool) – If True, quantities are converted to units instead of being passed through unchanged.

Return type:

Any

Returns:

An Annotated alias usable as a pydantic field type.

Note

Because this is a function call, static type checkers reject it inside an annotation. Use the equivalent Units spelling (Annotated[pint.Quantity, Units(ureg.m)]) where static checking matters.

Examples

>>> from pydantic import BaseModel
>>> class Sphere(BaseModel):
...     radius: quantity(ureg.m)
>>> Sphere(radius=1.0).radius
<Quantity(1.0, 'meter')>
>>> Sphere(radius={"value": 2.0, "units": "km"}).radius
<Quantity(2.0, 'kilometer')>

Incompatible units are rejected:

>>> Sphere(radius=1.0 * ureg.s)
Traceback (most recent call last):
  ...
pydantic_core._pydantic_core.ValidationError: ...

Units declared through a unit context are evaluated at validation time:

>>> uctx = UnitContext({"length": ureg.m})
>>> class Sphere(BaseModel):
...     radius: quantity(uctx.deferred("length"))
>>> with uctx.override(length="km"):
...     Sphere(radius=1.0).radius
<Quantity(1.0, 'kilometer')>

Serialization round-trips through the mapping form read by to_quantity():

>>> Sphere(radius=1.0).model_dump_json()
'{"radius":{"value":1.0,"units":"meter"}}'
pintext.pydantic.Quantity#

Any Pint quantity. Mappings and xarray DataArrays are interpreted with to_quantity(); no default units are applied and no compatibility check is performed. A value that cannot be interpreted as a quantity (e.g. bare float) is rejected.

Use Units or quantity() instead when the field has declared units.

alias of Annotated[Quantity, Units(None, convert=False)]