ucon.graph¶
ConversionGraph implementation, ContextVar-based scoping, and conversion exceptions.
ucon.graph — backward-compatibility shim.
All functionality has moved to :mod:ucon.conversion. This module
re-exports everything so existing from ucon.graph import ...
statements continue to work.
DimensionMismatch
¶
Bases: Exception
Raised when attempting to convert between incompatible dimensions.
ConversionNotFound
¶
Bases: Exception
Raised when no conversion path exists between units.
CyclicInconsistency
¶
Bases: Exception
Raised when adding an edge creates an inconsistent cycle.
Graph
dataclass
¶
Registry of conversion morphisms between units.
Stores edges between Unit nodes (partitioned by Dimension) and between UnitProduct nodes (for composite unit conversions like joule → watt_hour).
Supports: - Direct edge lookup - BFS path composition for multi-hop conversions - Factorwise decomposition for UnitProduct conversions - Graph-local unit name resolution (v0.7.3+) - Optional BasisGraph for cross-basis validation (v0.8.3+)
package_constants
property
¶
Constants materialized from loaded packages.
Returns¶
tuple[Constant, ...] All constants from loaded packages, in load order.
add_edge(*, src, dst, map, basis_transform=None, overwrite=False)
¶
Register a conversion edge (and its inverse) on this graph.
add_edge is the primary mechanism for extending a
:class:Graph with domain-specific units. Call it on
either the default package graph (ucon.graph.default_graph) or
your own Graph instance to wire new units into the
conversion system.
For every forward edge src → dst registered with :class:Map
m, the inverse dst → src is automatically registered using
m.inverse(). Adding an inconsistent inverse (one whose
round-trip is not the identity) raises
:exc:CyclicInconsistency. Adding an edge between units of
different dimensions without a basis_transform raises
:exc:DimensionMismatch.
Parameters¶
src : Unit or UnitProduct
Source unit expression. Both plain :class:Unit instances and
composite :class:UnitProduct expressions are accepted; the
graph dispatches to the appropriate edge-type internally.
dst : Unit or UnitProduct
Destination unit expression.
map : Map
The conversion morphism src → dst. Typically
:class:LinearMap for pure scalings, :class:AffineMap for
offset conversions (e.g., °C ↔ K), or :class:LogMap for
logarithmic units (dB, nepers).
basis_transform : BasisTransform or ConstantBoundBasisTransform, optional
For cross-basis edges (e.g., CGS ↔ SI when dimensional
exponents differ, as for electromagnetic units). The src
unit is rebased to the dst's dimension and the edge connects
the rebased unit to dst. Most edges do not need this.
overwrite : bool, optional
When True, remove any existing forward and inverse edges
for the (src, dst) pair before inserting the new ones.
This bypasses the cyclic-consistency check by clearing the
prior state first. Used by :func:_merge_conversion_graphs
under :attr:ConflictPolicy.PREFER_OTHER. Default False.
Raises¶
DimensionMismatch
src and dst have different dimensions and no
basis_transform was supplied.
CyclicInconsistency
A reverse edge exists already and composing it with the new
map does not yield the identity (only when
overwrite=False). This protects against silently
registering incompatible conversions.
NoTransformPath
The graph has a :class:BasisGraph attached and no path
exists between the source and destination bases.
Examples¶
Register a simple linear conversion on the default graph::
from ucon import units, LinearMap
from ucon.graph import default_graph
default_graph.add_edge(
src=units.mile,
dst=units.kilometer,
map=LinearMap(1.609344),
)
Register an affine temperature conversion::
from ucon import units, AffineMap
from ucon.graph import default_graph
default_graph.add_edge(
src=units.celsius,
dst=units.kelvin,
map=AffineMap(a=1.0, b=273.15),
)
Register a composite-unit edge (joule ↔ kWh)::
from ucon import units, LinearMap
from ucon.graph import default_graph
kwh = units.kilo * units.watt * units.hour
default_graph.add_edge(
src=units.joule,
dst=kwh,
map=LinearMap(1 / 3.6e6),
)
See Also¶
Graph.convert : Path-find between registered units. Graph.connect_systems : Bulk-add cross-basis edges. Number.to : User-facing conversion that delegates to this graph.
Notes¶
Stability: add_edge is part of the public API of
:mod:ucon as of v1.3.0. Its keyword-only signature
(src, dst, map, basis_transform) is considered
stable and will not change in a backwards-incompatible way
without a major-version bump.
connect_systems(*, basis_transform, edges)
¶
Bulk-add edges between systems.
Parameters¶
basis_transform : BasisTransform or ConstantBoundBasisTransform The transform bridging the two systems. edges : dict Mapping from (src_unit, dst_unit) to Map.
list_rebased_units()
¶
Return all rebased units in the graph.
Returns¶
dict[Unit, list[RebasedUnit]] Mapping from original unit to its RebasedUnit(s).
list_transforms()
¶
Return all BasisTransforms active in the graph.
Returns¶
list[BasisTransform] Unique transforms used by rebased units.
edges_for_transform(transform)
¶
register_unit(unit)
¶
Register a unit for name resolution within this graph.
Populates both case-insensitive and case-sensitive registries with the unit's name, shorthand, and aliases.
Parameters¶
unit : Unit The unit to register.
resolve_unit(name)
¶
Resolve a unit string in graph-local registry.
Only performs case-sensitive matching. Case-insensitive resolution
is handled by the global _lookup_factor() which applies the
correct priority chain (priority aliases → scale-prefix decomposition
→ case-sensitive → case-insensitive).
Returning a case-insensitive match here would short-circuit
scale-prefix decomposition, causing e.g. GB (giga-byte) to
resolve as Gb (gilbert) or nm (nano-meter) as nautical mile
(alias NM).
Parameters¶
name : str The unit name or alias to resolve.
Returns¶
tuple[Unit, Scale] | None (unit, Scale.one) if found, None otherwise. Caller should fall back to global registry if None.
contains_unit_by_identity(unit)
¶
Return True iff unit is registered in this graph by identity.
For a plain :class:Unit, returns True iff the exact object
(is-equal) appears as a node in any per-dimension edge map.
For a :class:UnitProduct, returns True iff every factor's
unit satisfies the same condition.
Unlike value-based dict lookup (which uses __eq__ / __hash__),
this method iterates with is-comparison so that two
structurally-equal :class:Unit instances with the same
(name, dimension, aliases) are not considered the same node.
This is the semantics required by strict=True source-unit
resolution in :meth:ucon.Number.to: a :class:Number whose
unit is value-equal but identity-distinct from any node in the
active graph must surface a :exc:UnitDefinitionMismatch rather
than silently re-resolve via name.
Parameters¶
unit : Unit or UnitProduct The unit expression to check.
Returns¶
bool
True iff every constituent :class:Unit is is-equal
to a node already registered in _unit_edges.
copy()
¶
Return a deep copy suitable for extension.
Creates independent copies of edge dictionaries and name registries. The returned graph can be modified without affecting the original.
Returns¶
Graph A new graph with copied state.
register_context(ctx)
¶
Register a named conversion context for serialization.
Parameters¶
ctx : ConversionContext A frozen context to store by name.
with_package(package)
¶
Return a new graph with this package's units and edges added.
Creates a copy of this graph and applies the package contents. The original graph is not modified.
Parameters¶
package : UnitPackage Package containing unit and edge definitions.
Returns¶
Graph New graph with package contents added.
Example¶
from ucon.packages import load_package aero = load_package("aerospace.ucon.toml") graph = get_default_graph().with_package(aero)
convert(*, src, dst)
¶
Find or compose a conversion Map from src to dst.
Parameters¶
src : Unit or UnitProduct Source unit expression. dst : Unit or UnitProduct Destination unit expression.
Returns¶
Map The conversion morphism.
Raises¶
DimensionMismatch If src and dst have different dimensions. ConversionNotFound If no conversion path exists.
to_toml(path, *, kinds=None, formulas=None, aspects=None)
¶
Export this graph to a TOML file.
Parameters¶
path : str or Path
Destination file path.
kinds : KindLattice or None
Optional kind lattice to serialize as [[kinds]] sections.
formulas : FormulaRegistry or None
Optional formula registry to serialize as [[formulas]]
sections.
aspects : AspectForest or None
Optional aspect forest to serialize as [[aspects]]
sections.
Raises¶
ImportError
If tomli_w is not installed.
from_toml(path, *, strict=True)
classmethod
¶
__eq__(other)
¶
Compare graphs for structural equality.
Two graphs are equal if they have the same registered unit names, the same edge conversions (within tolerance), the same loaded packages, the same constants, and the same contexts.
get_default_graph()
¶
Get the current conversion graph.
Priority:
1. Context-local graph (from using_conversion_graph)
2. Active :class:~ucon.system.UnitSystem's conversion_graph
using_conversion_graph(graph)
¶
Context manager for scoped :class:Graph override.
Sets both the conversion graph and parsing graph contexts, so that name resolution and conversions both use the same graph.
Usage::
with using_conversion_graph(custom_graph):
result = value.to(target) # uses custom_graph
unit = parse_unit("custom_unit") # resolves in custom_graph
Parameters¶
graph : Graph The graph to use within this context.
Yields¶
Graph The same graph passed in.