ucon.system¶
System-level value types: BaseUnits (the renamed v1.7 UnitSystem), the new UnitSystem value type, the per-instance AlgebraCache, and the use / active activation surface.
ucon.system¶
System-level value types for ucon.
This subpackage hosts the abstractions that record which units, dimensions, conversions, and basis transforms a coherent unit system uses.
Public surface (v1.8):
- :class:
BaseUnits-- a small namedMapping[Dimension, Unit]that records the canonical base unit per dimension. The renamed predecessor of the v1.7 top-levelUnitSystemclass. - :class:
UnitSystem-- the new value type that owns aBaseUnitsplus the registries (units, dimensions, conversions, basis_graph, contexts, constants) and a per-instance :class:AlgebraCache. - :class:
AlgebraCache-- per-instance cache forDimensionalgebra (mul/div/pow). - :func:
use-- contextmanager that sets the activeUnitSystem. - :func:
active-- returns the activeUnitSystem(snapshotting from globals if none has been set).
The PEP-562 alias from ucon import UnitSystem continues to resolve to
:class:BaseUnits in v1.8 with a PendingDeprecationWarning. The new
value type is reachable only via from ucon.system import UnitSystem.
AlgebraCache
dataclass
¶
Per-instance cache for Dimension algebraic operations.
Holds three sub-caches keyed by argument tuples:
mul:(Dimension, Dimension) -> Dimensiondiv:(Dimension, Dimension) -> Dimensionpow:(Dimension, exponent) -> Dimension
Owned by each :class:~ucon.system.UnitSystem instance.
clear()
¶
Empty all three sub-caches.
ConflictPolicy
¶
Bases: Enum
Policy for resolving name collisions when combining two
:class:UnitSystem values.
- :attr:
RAISE(default): raise :class:ExtendConflicton any collision. - :attr:
PREFER_SELF: keep the LHS definition; ignore the RHS. - :attr:
PREFER_OTHER: replace the LHS definition with the RHS.
ExtendConflict
¶
Bases: ValueError
Raised when :meth:UnitSystem.extend finds a name collision under
:attr:ConflictPolicy.RAISE policy.
The registry attribute names the registry in which the conflict
occurred ("units", "dimensions", "base_units",
"conversions", "contexts", or "constants"); key is the
colliding name.
InvalidRename
¶
Bases: ValueError
Raised when :class:Bridge is constructed with a rename pair that
is not synonym-equivalent.
A pair (src_name, dst_name) is synonym-equivalent only when
src.units[src_name] and dst.units[dst_name] represent the
same physical unit -- same dimension (under basis_transform when
one is supplied) and identical base form. Definitional differences
must be expressed via basis_transform or a custom conversion
edge, not via rename.
Attributes¶
src_name : str The source-side rename key. dst_name : str The destination-side rename value. reason : str Why the pair is not synonym-equivalent.
RegistryDiff
dataclass
¶
Per-registry diff payload for :class:SystemDiff.
Attributes¶
added : frozenset[str]
Keys present in other but not in self.
removed : frozenset[str]
Keys present in self but not in other.
redefined : frozenset[str]
Keys present in both with non-equal values.
SystemDiff
dataclass
¶
Structured difference between two :class:UnitSystem values.
Returned by :meth:UnitSystem.diff. Each field is a
:class:RegistryDiff describing additions, removals, and
redefinitions in that registry as self -> other.
BaseUnits
dataclass
¶
A named mapping from dimensions to base units.
Represents a coherent unit system like SI or Imperial, where each covered dimension has exactly one base unit. Partial systems are allowed (Imperial doesn't need mole).
Parameters¶
name : str The name of the unit system (e.g., "SI", "Imperial"). bases : dict[Dimension, Unit] Mapping from dimensions to their base units.
Raises¶
ValueError If name is empty, bases is empty, or a unit's dimension doesn't match its declared dimension key.
Examples¶
si = BaseUnits( ... name="SI", ... bases={ ... LENGTH: meter, ... MASS: kilogram, ... TIME: second, ... } ... ) si.base_for(LENGTH)
UnitSystem
dataclass
¶
A complete unit system as a value type.
Owns the basis, the registries (units, dimensions, conversion_graph,
basis_graph, contexts, constants), the canonical base_units
mapping, and a per-instance :class:AlgebraCache.
Parameters¶
basis : Basis Dimensional coordinate system. units : Mapping[str, Unit] Name registry of units. dimensions : Mapping[str, Dimension] Name registry of dimensions. base_units : BaseUnits Canonical base unit per covered dimension. conversion_graph : ConversionGraph Graph of unit conversion morphisms. basis_graph : BasisGraph Graph of basis transforms. contexts : Mapping[str, ConversionContext] Named cross-dimensional context bundles. Defaults to empty. constants : Mapping[str, Constant] Physical constants registry. Defaults to empty. _algebra_cache : AlgebraCache Per-instance dimension-algebra cache. Constructed empty by default.
Notes¶
The frozen dataclass holds references to mutable registries (dicts and
graph objects). "Frozen" applies to the field bindings, not the
contents of the registries -- mirroring how :class:BaseUnits already
treats its bases dict. Equality and hash use identity for the
mutable mappings/graphs and value equality for basis and
base_units; the per-instance _algebra_cache is excluded from
both.
resolve_unit(name)
¶
Resolve a unit name/alias/expression string to a Unit or UnitProduct.
Delegates to :func:~ucon.resolver.parse_unit with system=self
so the resolver draws from this system's unit registry.
Parameters¶
name : str
Unit name, alias, scale-prefixed name, or composite expression
(e.g., "ft", "km", "kg*m/s^2").
Returns¶
Unit or UnitProduct The resolved unit.
Raises¶
UnknownUnitError If the string cannot be resolved.
extend(other, *, on_conflict=ConflictPolicy.RAISE)
¶
Return a new system combining self and other.
Unions each registry (units, dimensions, base_units, conversion
edges, contexts, constants). Name collisions are resolved by
on_conflict (a :class:ConflictPolicy member):
- :attr:
ConflictPolicy.RAISE(default): raise :class:ExtendConflictif any registry has two non-equal definitions for the same name. Identical values do not trigger the error. - :attr:
ConflictPolicy.PREFER_SELF: keep the LHS value on conflict; the RHS value is silently discarded. - :attr:
ConflictPolicy.PREFER_OTHER: replace the LHS value with the RHS value.
self.basis and self.basis_graph are preserved unchanged.
Use :meth:with_basis / :meth:with_basis_graph to change them
explicitly.
extend_many(*others, on_conflict=ConflictPolicy.RAISE)
¶
Return a new system combining self with all others.
Semantically equivalent to chaining .extend() calls but
performs a single conversion-graph copy regardless of how many
systems are merged. This avoids the O(N * graph_size) cost of
sequential extend() when composing many packages.
Parameters¶
*others : UnitSystem
One or more systems to merge into self.
on_conflict : ConflictPolicy
Collision resolution strategy (same semantics as
:meth:extend).
restrict(*, dimensions=None, units=None)
¶
Return a new system retaining only the named dimensions and units.
Either filter may be None to leave that registry unrestricted.
Filters compose: a unit survives only if both filters admit it.
The conversion graph is filtered to edges whose endpoints survive.
base_units is filtered to entries whose dimension and unit
survive. basis, basis_graph, contexts, and
constants are preserved unchanged.
merge(other, resolver)
¶
Return a new system combining self and other with a
callable resolver for unit-name conflicts.
For every unit name shared between self.units and
other.units whose values are non-equal, the resolver is invoked
as resolver(self_unit, other_unit) and must return one of the
two units (or a structurally-equal alternative). All other
registries (dimensions, base_units, conversion edges, contexts,
constants) use :attr:ConflictPolicy.PREFER_SELF semantics on
conflict.
The resolver is not called for keys present in only one side or for keys whose values are already equal.
with_unit(unit)
¶
Return a new system with unit added to the units registry.
If a unit with the same name already exists and is structurally
equal, returns self unchanged. Otherwise raises
:class:ExtendConflict on a non-equal collision.
with_conversion(edge)
¶
Return a new system with edge added to the conversion graph.
Accepts the existing :class:ucon.contexts.ContextEdge value type
(src, dst, map). Edges are bidirectional; the inverse is
registered automatically by :meth:Graph.add_edge. Re-adding an
identical edge is a no-op.
with_basis(basis)
¶
Return a new system whose basis is replaced.
basis_graph is preserved as-is; callers are responsible for
ensuring it contains the new basis (otherwise cross-basis
operations from this system will fail at use time, not at
construction).
with_basis_graph(graph)
¶
Return a new system whose basis_graph is replaced.
subsystem_of(other)
¶
Return True iff every unit, dimension, base-unit mapping, and
conversion edge in self exists with the same definition in
other.
basis and basis_graph are not compared; subsystem is a
registry-content relation.
compatible_with(other)
¶
Return True iff self and other agree wherever they
overlap.
Every shared unit name maps to equal :class:Unit definitions;
every shared dimension name maps to equal :class:Dimension
definitions; every shared base-unit dimension maps to equal
:class:Unit; every shared conversion edge (by endpoint-name)
maps to the same :class:Map. Non-overlapping registry entries
are ignored.
diff(other)
¶
Return a :class:SystemDiff describing self -> other.
Each registry contributes a :class:RegistryDiff with added
(in other but not self), removed (in self but not
other), and redefined (in both with non-equal values).
shared_units(other)
¶
Return the set of unit names defined in both systems.
shared_dimensions(other)
¶
Return the set of dimension names defined in both systems.
adopt(n)
¶
Rebind n to use this system's :class:Unit objects.
Walks n.unit (a :class:Unit or :class:UnitProduct) and
checks that every component-unit name resolves in
self.units. Returns a new :class:Number whose unit
references point at the objects owned by this system; the
numeric quantity and uncertainty are unchanged.
adopt performs no conversion. It is the trivial value-
movement primitive for the case where unit names already match
between systems. When names diverge or numeric correction is
needed, use :class:Bridge.
Parameters¶
n : Number The value to re-bind.
Returns¶
Number
A :class:Number whose unit references this system's
:class:Unit objects.
Raises¶
UnknownUnitError
If any component unit name is not defined in self.units.
ActiveContext
dataclass
¶
The ambient state bundle consulted by ucon's runtime.
A single :class:~contextvars.ContextVar (ucon._active) carries
one :class:ActiveContext at a time. The payload bundles the
:class:UnitSystem (units, dimensions, graphs) with the
:class:~ucon.formulas.FormulaRegistry (kind-aware arithmetic
dispatch table), the :class:~ucon.kinds.KindLattice (kind taxonomy
consulted by Number.bound_to etc.), and strict (source-unit
resolution mode for :meth:Number.to and arithmetic).
Keeping formulas and kinds off :class:UnitSystem is
deliberate: a system does not own its formulas, and an
:class:ActiveContext lets the caller swap the dispatch table
without rebuilding the system.
Attributes¶
system : UnitSystem
The active unit system.
formulas : FormulaRegistry
Kind-aware arithmetic dispatch table.
kinds : KindLattice
Kind taxonomy.
strict : bool
Whether source-unit resolution is identity-based (True,
v2.0 default) or falls back to name-based lookup (False,
v1.x ergonomics).
Bridge
dataclass
¶
Sanctioned cross-system value movement.
A Bridge carries a :class:~ucon.core.Number from src to
dst, applying optional unit-name renames (synonym-equivalent
pairs only) and an optional :class:~ucon.basis.BasisTransform for
cross-basis rebasing.
Rename is synonym-only: each (a, b) in rename must
satisfy src.units[a] and dst.units[b] representing the same
physical unit. Definitional remapping (two systems naming distinct
units identically) must be expressed via basis_transform or a
custom conversion edge; it is rejected at construction with
:class:InvalidRename.
Apply order is rename → basis_transform → identity-bind to dst
:class:Unit. Under the synonym constraint the two layers commute;
the order is pinned for trace-readability.
Attributes¶
src : UnitSystem The source system. dst : UnitSystem The destination system. rename : Mapping[str, str] Synonym-equivalent unit-name pairs. basis_transform : BasisTransform, optional Optional coordinate change for cross-basis values.
apply(n)
¶
Move n from :attr:src to :attr:dst.
Order: rename (name layer) → basis_transform (numeric
layer; no-op under the synonym constraint) → identity-bind to
:attr:dst's :class:Unit objects. The result is a new
:class:Number whose units reference :attr:dst's registry.
Raises¶
UnknownUnitError
If a component-unit name (after rename) is not in
self.dst.units.
inverse()
¶
Return the reverse bridge dst → src.
Renames are reversed; basis_transform is inverted; the
result is re-validated by :meth:__post_init__.
__matmul__(other)
¶
Compose self @ other: apply other first, then self.
Requires other.dst is self.src (registry identity). The
composed rename chains source names through other to
self; the composed basis_transform is
self.basis_transform @ other.basis_transform when both are
present.
The resulting :class:Bridge is re-validated by
:meth:__post_init__ so that pairs valid individually but not
jointly are caught.
active()
¶
Return the currently active :class:ActiveContext.
After import ucon, the active context is always set via eager
initialization.
.. versionchanged:: 2.0
Returns :class:ActiveContext instead of :class:UnitSystem.
Use :func:active_system for the prior semantics.
Raises¶
RuntimeError
If called before import ucon has completed (i.e. the eager
init block in ucon/__init__.py has not yet run).
active_system()
¶
Return the active :class:UnitSystem.
Convenience accessor equivalent to active().system. Replaces the
pre-v2.0 active() semantics.
active_formulas()
¶
Return the active :class:~ucon.formulas.FormulaRegistry.
Convenience accessor equivalent to active().formulas.
active_kinds()
¶
Return the active :class:~ucon.kinds.KindLattice.
Convenience accessor equivalent to active().kinds.
active_strict()
¶
Return the active source-unit resolution mode.
Convenience accessor equivalent to active().strict.
use(system, *, formulas=None, kinds=None, strict=None)
¶
Set the active :class:ActiveContext for the with-block.
Constructs an :class:ActiveContext with the given system and
inherits formulas, kinds, and strict from the enclosing
context when those kwargs are not supplied. On exit the prior
context is restored.
Parameters¶
system : UnitSystem
The system to activate for the duration of the with-block.
formulas : FormulaRegistry, optional
Override the formulas registry. Inherits from the enclosing
context when None.
kinds : KindLattice, optional
Override the kind lattice. Inherits from the enclosing context
when None.
strict : bool, optional
Override source-unit resolution mode. Inherits from the
enclosing context when None.
Examples¶
sys = active_system() with use(sys) as ctx: ... assert ctx.system is sys