diff --git a/pyproject.toml b/pyproject.toml index cd85834..da07d24 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -191,6 +191,7 @@ "protected-access", # handled by ruff "redefined-builtin", # handled by ruff "too-many-function-args", # plum-dispatch + "unexpected-keyword-arg", # plum-dispatch "unused-argument", # handled by ruff "wrong-import-order", # handled by ruff "wrong-import-position", diff --git a/src/unxt/_quantity/base.py b/src/unxt/_quantity/base.py index a851ed4..570c6fa 100644 --- a/src/unxt/_quantity/base.py +++ b/src/unxt/_quantity/base.py @@ -3,7 +3,7 @@ __all__ = ["AbstractQuantity", "can_convert_unit"] -from collections.abc import Callable, Sequence +from collections.abc import Callable, Mapping, Sequence from dataclasses import fields, replace from typing import TYPE_CHECKING, Any, ClassVar, TypeAlias, TypeGuard, TypeVar @@ -219,6 +219,43 @@ def constructor( # Dispatched on no argument. Dispatch to the full constructor. return cls.constructor(value, unit, dtype=dtype) + @classmethod # type: ignore[no-redef] + @dispatcher + def constructor( + cls: "type[AbstractQuantity]", mapping: Mapping[str, Any] + ) -> "AbstractQuantity": + """Construct a `Quantity` from a Mapping. + + Parameters + ---------- + mapping : Mapping[str, Any] + Mapping of the fields of the `Quantity`, e.g. 'value' and 'unit'. + + Returns + ------- + AbstractQuantity + + Examples + -------- + For this example we'll use the `Quantity` class. The same applies to + any subclass of `AbstractQuantity`. + + >>> import jax.numpy as jnp + >>> from unxt import Quantity + + >>> x = jnp.array([1.0, 2, 3]) + >>> q = Quantity.constructor({"value": x, "unit": "m"}) + >>> q + Quantity['length'](Array([1., 2., 3.], dtype=float32), unit='m') + + >>> Quantity.constructor({"value": q, "unit": "km"}) + Quantity['length'](Array([0.001, 0.002, 0.003], dtype=float32), unit='km') + + """ + # Dispatch on both arguments. + # Construct using the standard `__init__` method. + return cls.constructor(**mapping) + # See below for additional constructors. # ===============================================================