Migrating to v2#
This guide covers the breaking changes introduced in unxt v2: the rename of the quantity classes and the extraction of the parametric quantity into the separate unxts.parametric package. If you are starting fresh with unxt, you do not need this guide β consult the Quantity guide and the parametric quantity guide for the current API.
Class Rename Mapping#
v1 name |
v2 name |
Short alias |
Notes |
|---|---|---|---|
|
|
|
Now the default, non-parametric class |
|
|
|
Opt-in; moved to the |
β |
|
|
New alias for |
β |
|
|
New alias for |
Note
As of v2, ParametricQuantity/PQ live in the separate unxts.parametric
package rather than in unxt. Install it with pip install unxts.parametric
and import as import unxts.parametric as up (so up.PQ). Accessing
unxt.ParametricQuantity / u.PQ now raises an AttributeError pointing here.
Package Split: ParametricQuantity Moved to unxts.parametric#
In v2 the parametric quantity classes live in a separate package, unxts.parametric, rather than in unxt. Core unxt no longer imports or depends on ParametricQuantity at all. Install the package to opt in:
pip install unxts.parametric # or: uv add unxts.parametric
Accessing the moved names on unxt now raises AttributeError with a message pointing to the new package β this covers unxt.ParametricQuantity, unxt.PQ, unxt.AbstractParametricQuantity, and their unxt.quantity.* equivalents.
Update your imports#
v1 ( |
v2 ( |
|---|---|
|
|
|
|
|
|
|
|
# Before (v1)
import unxt as u
q = u.PQ(1, "m")
# After (v2)
import unxts.parametric as up
q = up.PQ(1, "m")
Angle operations now return the default Quantity#
Trigonometric and product operations on an Angle (cos, sin, tan, cbrt, Angle @ Angle, Angle * Angle, integer/array powers, etc.) previously produced a ParametricQuantity. Because core unxt can no longer reference the parametric class, in v2 they produce the lightweight default Quantity:
import unxt as u
import quaxed.numpy as jnp
jnp.cos(u.Angle(0, "deg")) # v1: ParametricQuantity(...) -> v2: Quantity(...)
u.Angle([1, 2, 3], "deg") @ u.Angle([4, 5, 6], "deg") # now a Quantity
The value and unit are unchanged β only the wrapping class differs. If you specifically need a parametric result, convert explicitly with convert(result, up.PQ).
Parametric operands need unxts.parametric imported#
A few JAX primitive rules fire only when a parametric quantity is involved β raising a quantity to a dimensionless ParametricQuantity exponent, % (remainder), and clamp with parametric bounds. These rules are registered as an import side effect of unxts.parametric. Importing the package (which you do to use up.PQ at all) registers them; if a ParametricQuantity reaches your code some other way, import unxts.parametric once at startup.
Astropy conversion#
Converting an astropy.units.Quantity to a ParametricQuantity is now registered by unxts.parametric (import it to enable). Conversion to the default Quantity remains in core unxt:
from astropy.units import Quantity as AstropyQuantity
from plum import convert
import unxt as u
import unxts.parametric as up
convert(AstropyQuantity(1.0, "cm"), u.Quantity) # core unxt
convert(AstropyQuantity(1.0, "cm"), up.PQ) # needs unxts.parametric
Config: include_params moved to unxts.parametric.config#
The include_params display option β whether repr()/str() show the ['length']-style dimension parameter β only affects parametric quantities, so it moved out of unxt.config into unxts.parametric.config. unxt.config now rejects it as an unknown option.
v1 ( |
v2 ( |
|---|---|
|
|
|
|
|
|
Defaults are unchanged (repr hides the parameter, str shows it). The other display settings (short_arrays, use_short_name, named_unit, indent) remain in unxt.config. See the parametric quantity guide.
Config file section renamed to [tool.unxts.unxt]#
unxtβs pyproject.toml display configuration moved from [tool.unxt...] to [tool.unxts.unxt...], matching the shared unxts.* namespace (alongside [tool.unxts.parametric...]). Rename any existing sections:
v1 |
v2 |
|---|---|
|
|
|
|
In-code configuration via u.config is unchanged.
Deprecation: BareQuantity#
BareQuantity is now a deprecated alias of Quantity. Accessing it emits a DeprecationWarning and returns the (new) Quantity class:
import warnings
import unxt as u
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
BQ = u.quantity.BareQuantity # DeprecationWarning
assert BQ is u.Quantity # same class
print(w[0].category.__name__) # DeprecationWarning
BareQuantity will be removed in a future release. Update your code now:
# Before (v1)
from unxt import BareQuantity
q = BareQuantity(1.0, "m")
# After (v2)
from unxt import Quantity # or: import unxt as u; u.Q(...)
q = Quantity(1.0, "m")
Behavioral Changes for Former Quantity Users#
If you used the old parametric Quantity, two behaviors have changed:
(a) Subscripting no longer dimension-checks by default#
In v1, Quantity["length"](1, "s") would raise a ValueError because "s" (seconds) is not a length unit. In v2, the same call on the new default Quantity accepts any unit without checking:
import unxt as u
import unxts.parametric as up
# v2 default Quantity β subscript is a no-op, no check
u.Q["length"](1, "s") # Quantity(1, unit='s') β no error
# ParametricQuantity β still raises on mismatch
try:
up.PQ["length"](1, "s")
except ValueError as e:
print(e) # Physical type mismatch.
Migration: Replace Quantity["<dim>"](...) calls that relied on dimension checking with ParametricQuantity["<dim>"](...) (or up.PQ["<dim>"](...)).
(b) Plum dispatch on dimension-specific types requires ParametricQuantity#
In v1, Quantity["length"] was a distinct class usable in plum dispatch annotations. In v2, u.Q["length"] is u.Quantity β subscripting the default Quantity returns the same class, making it useless for dimension-based dispatch.
# v1 dispatch on old Quantity (broken in v2)
# @dispatch
# def f(x: Quantity["length"]): ... # was a distinct type in v1
# v2 β use ParametricQuantity for dimension-specific dispatch
from plum import dispatch
import unxts.parametric as up
@dispatch
def f(x: up.PQ["length"]):
return "length!"
@dispatch
def f(x: up.PQ["time"]):
return "time!"
Why the Default Changed: Pytree Types, Not JIT Cache Misses#
The motivation for making the non-parametric class the default is how it interacts with JAXβs pytree machinery β but it is worth being precise about what does and does not change.
ParametricQuantity encodes the physical dimension in its type: ParametricQuantity["length"] and ParametricQuantity["time"] are distinct Python classes, created on demand, and each is registered as its own JAX pytree node type. The new default Quantity is a single class β and a single pytree node type β for every dimension.
What this does not change: jax.jit recompilation. A quantityβs unit is a static field, so it lives in the pytree aux data (the treedef), which is part of the jit cache key. A jitted function therefore specializes per distinct unit with either class β a function compiled for a length quantity in metres is not reused for a time quantity in seconds, because their units (and treedefs) differ. Since a unit already implies its dimension, ParametricQuantityβs per-dimension class is redundant with the per-unit key and adds no extra compilations. The two classes produce the same number of jit compilations for the same inputs.
What it does change: the cost of the type proliferation itself. With ParametricQuantity, every physical dimension you touch:
creates a new Python class the first time it is used (via
plumβs parametric machinery),registers a new JAX pytree node type and grows
plumβs dispatch tables, all of which must be tracked and searched, andpays a per-construction cost for dimension inference and the
__check_init__validation.
The single-class Quantity avoids all of that: one class, one registered pytree type, no on-the-fly class creation, and a lighter construction/dispatch path. That is the efficiency win β a smaller, simpler type surface and cheaper per-operation overhead β rather than fewer jit compilations.
ParametricQuantity remains available β and is the right choice β when you genuinely need:
Runtime dimension checking:
up.PQ["length"](1, "s")raises immediately.Dimension-specific
plumdispatch:up.PQ["length"]is a distinct type.
For everything else β arithmetic, unit conversion, JAX transforms, interop β Quantity and ParametricQuantity behave identically.
Note on Pickles#
Old pickles that reference the private module path unxt._src.quantity.quantity.Quantity resolve to the new Quantity class (i.e. the former BareQuantity). If you have pickles that stored instances of the old parametric Quantity (now ParametricQuantity), they will deserialize as the wrong type. Re-generate those pickles after upgrading.