ucon.core¶
Core types for representing units, quantities, and dimensional constraints.
ucon.core¶
Implements the ontological core of the ucon system — the machinery that defines the algebra of physical dimensions, magnitude prefixes, and units.
Classes¶
- :class:
Dimension— Physical dimensions with algebraic closure over *, /, and ** - :class:
Scale— Enumerates SI and binary magnitude prefixes with algebraic closure over *, / and with nearest-prefix lookup. - :class:
Unit— Measurable quantity descriptor with algebraic closure over *, /. - :class:
UnitProduct— Product/quotient of Units with simplification and readable rendering.
DimensionNotCovered
¶
Bases: Exception
Raised when a UnitSystem doesn't cover a requested dimension.
UnknownUnitError
¶
Bases: Exception
Raised when a unit string cannot be resolved to a known unit.
Exponent
¶
Represents a base–exponent pair (e.g., 10³ or 2¹⁰).
Provides comparison and division semantics used internally to represent magnitude prefixes (e.g., kilo, mega, micro).
evaluated
property
¶
Return the numeric value of base ** power.
parts()
¶
Return (base, power) tuple, used for Scale lookups.
__truediv__(other)
¶
Divide two Exponents. - If bases match, returns a relative Exponent. - If bases differ, returns a numeric ratio (float).
__pow__(exponent)
¶
Raise this Exponent to a numeric power.
Scale
¶
Bases: Enum
by_value()
cached
staticmethod
¶
Return a map from evaluated numeric value → Scale name. Cached after first access.
Unit
dataclass
¶
Represents a unit of measure associated with a :class:Dimension.
A Unit is an atomic symbol with no scale information. Scale is handled separately by UnitFactor, which pairs a Unit with a Scale.
Parameters¶
name : str Canonical name of the unit (e.g., "meter"). dimension : Dimension The physical dimension this unit represents. aliases : tuple[str, ...] Optional shorthand symbols (e.g., ("m", "M")).
shorthand
property
¶
Symbol used in expressions (e.g., 'm', 's'). For dimensionless units, returns ''.
Note: Scale prefixes are handled by UnitFactor.shorthand, not here.
basis
property
¶
The dimensional basis this unit belongs to.
is_compatible(other, basis_graph=None)
¶
Check if this unit is compatible with another for conversion.
Two units are compatible if: 1. They have the same dimension, OR 2. Their bases are connected via the BasisGraph (cross-basis conversion)
Parameters¶
other : Unit The other unit to check compatibility with. basis_graph : BasisGraph, optional The basis graph to use for cross-basis compatibility checks. If None, only same-dimension compatibility is checked.
Returns¶
bool True if the units can be converted between each other.
Examples¶
from ucon import units, BasisGraph units.meter.is_compatible(units.foot) True units.meter.is_compatible(units.second) False
__mul__(other)
¶
Unit * Unit -> UnitProduct Unit * UnitProduct -> UnitProduct
__truediv__(other)
¶
Unit / Unit or Unit / UnitProduct => UnitProduct
__pow__(power)
¶
Unit ** n => UnitProduct with that exponent.
__repr__()
¶
__call__(quantity, uncertainty=None)
¶
Create a Number or NumberArray with this unit.
Parameters¶
quantity : int, float, list, tuple, or numpy.ndarray The numeric value(s). If array-like, returns NumberArray. uncertainty : float, array-like, or None The measurement uncertainty.
Returns¶
Number or NumberArray Number for scalar inputs, NumberArray for array inputs.
Example¶
meter(5) <5 m> meter(1.234, uncertainty=0.005) <1.234 ± 0.005 m> meter([1, 2, 3]) # requires numpy
UnitSystem
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 = UnitSystem( ... name="SI", ... bases={ ... LENGTH: meter, ... MASS: kilogram, ... TIME: second, ... } ... ) si.base_for(LENGTH)
RebasedUnit
dataclass
¶
A unit whose dimension was transformed by a BasisTransform.
Lives in the destination partition but preserves provenance to the original unit and the transform that created it.
Parameters¶
original : Unit The original unit before transformation. rebased_dimension : Dimension The dimension in the destination system. basis_transform : ucon.basis.BasisTransform or ucon.basis.transforms.ConstantBoundBasisTransform The transform that rebased this unit (from ucon.basis module).
Examples¶
rebased = RebasedUnit( ... original=statcoulomb, ... rebased_dimension=Dimension.charge, ... basis_transform=esu_to_si, ... ) rebased.dimension
rebased.name 'statcoulomb'
UnitFactor
dataclass
¶
A structural pair (unit, scale) used as the key inside UnitProduct.
unitis a plain Unit (no extra meaning beyond dimension + aliases + name).scaleis the expression-level Scale attached by the user (e.g. milli in mL).
Two UnitFactors are equal iff both unit and scale are equal, so components
with the same base unit and same scale truly merge.
NOTE: We also implement equality / hashing in a way that allows lookups by the underlying Unit to keep working:
m in product.factors
product.factors[m]
still work even though the actual keys are UnitFactor instances.
shorthand
property
¶
Render something like 'mg' for UnitFactor(gram, milli), or 'L' for UnitFactor(liter, one).
UnitProduct
¶
Represents a product or quotient of Units.
Key properties: - factors is a dict[UnitFactor, float] mapping (unit, scale) pairs to exponents. - Nested UnitProduct instances are flattened. - Identical UnitFactors (same underlying unit and same scale) merge exponents. - Units with net exponent ~0 are dropped. - Dimensionless units (NONE) are dropped. - Scaled variants of the same base unit (e.g. L and mL) are grouped by (name, dimension, aliases) and their exponents combined; if the net exponent is ~0, the whole group is cancelled.
shorthand
property
¶
Human-readable composite unit string, e.g. 'kg·m/s²'.
__init__(factors)
¶
Build a UnitProduct with UnitFactor keys, preserving user-provided scales.
Key principles: - Never canonicalize scale (no implicit preference for Scale.one). - Only collapse scaled variants of the same base unit when total exponent == 0. - If only one scale variant exists in a group, preserve it exactly. - If multiple variants exist and the group exponent != 0, preserve the FIRST encountered UnitFactor (keeps user-intent scale).
fold_scale()
¶
Compute the overall numeric scale factor of this UnitProduct by folding together the scales of each UnitFactor raised to its exponent, plus any residual scale factor from cancelled units.
Returns¶
float The combined numeric scale factor.
from_unit(unit)
classmethod
¶
Wrap a plain Unit as a UnitProduct with Scale.one (cached).
factors_by_dimension()
¶
Group factors by dimension.
Returns a dict mapping each Dimension to (UnitFactor, exponent). Raises ValueError if multiple factors share the same Dimension.
__pow__(power)
¶
UnitProduct ** n => new UnitProduct with scaled exponents.
__call__(quantity, uncertainty=None)
¶
Create a Number or NumberArray with this unit product.
Parameters¶
quantity : int, float, list, tuple, or numpy.ndarray The numeric value(s). If array-like, returns NumberArray. uncertainty : float, array-like, or None The measurement uncertainty.
Returns¶
Number or NumberArray Number for scalar inputs, NumberArray for array inputs.
Example¶
(meter / second)(10) <10 m/s> (meter / second)(10, uncertainty=0.5) <10 ± 0.5 m/s> (meter / second)([10, 20, 30]) # requires numpy
DimensionConstraint
¶
Annotation marker: constrains a Number to a specific Dimension.
Used with typing.Annotated to enable Number[TIME] syntax. The decorator @enforce_dimensions introspects this marker at runtime.
Number
dataclass
¶
Represents a numeric quantity with an associated :class:Unit and :class:Scale.
Combines magnitude, unit, and scale into a single, composable object that supports dimensional arithmetic and conversion:
>>> from ucon.units import meter, second
>>> length = meter(5)
>>> time = second(2)
>>> speed = length / time
>>> speed
<2.5 m/s>
Optionally includes measurement uncertainty for error propagation:
>>> length = meter(1.234, uncertainty=0.005)
>>> length
<1.234 ± 0.005 m>
value
property
¶
Return the numeric magnitude as-expressed (no scale folding).
Scale lives in the unit expression (e.g. kJ, mL) and is NOT
folded into the returned value. Use unit.fold_scale() on a
UnitProduct when you need the base-unit-equivalent magnitude.
__class_getitem__(dim)
¶
Enable Number[Dimension.X] syntax for type annotations.
Returns Annotated[Number, DimensionConstraint(dim)] for runtime introspection by @enforce_dimensions decorator.
simplify()
¶
Return a new Number expressed in base scale (Scale.one).
This normalizes the unit expression by removing all scale prefixes and adjusting the quantity accordingly. No conversion graph is needed since this is purely a scale transformation.
Examples¶
from ucon import Scale, units km = Scale.kilo * units.meter km(5).simplify() <5000 m> mg = Scale.milli * units.gram mg(500).simplify() <0.5 g>
to(target, graph=None)
¶
Convert this Number to a different unit expression.
Parameters¶
target : Unit, UnitProduct, or str
The target unit to convert to. Strings are resolved via
:func:~ucon.resolver.get_unit_by_name, which supports bare names
("foot"), aliases ("ft"), scale prefixes ("km"),
and composite expressions ("m/s²").
graph : ConversionGraph, optional
The conversion graph to use. If not provided, uses the default graph.
Returns¶
Number A new Number with the converted quantity and target unit.
Examples¶
from ucon.units import meter, foot length = meter(100) length.to(foot) <328.084 ft> length.to("ft") <328.084 ft> length.to("km") <0.1 km>
Ratio
¶
Represents a ratio of two Numbers, preserving their unit semantics.
Useful for expressing physical relationships like efficiency, density, or dimensionless comparisons:
>>> ratio = Ratio(length, time)
>>> ratio.evaluate()
<2.5 m/s>
evaluate()
¶
Evaluate the ratio to a Number.
Uses Exponent-derived arithmetic for scale handling: - If the result is dimensionless (units cancel), scales are folded into the magnitude using _canonical_magnitude. - If the result is dimensionful, raw quantities are divided and unit scales are preserved symbolically.
This matches the behavior of Number.truediv for consistency.