Skip to main content

ucon

Pronounced: yoo · cahn

tests codecov publish

A lightweight, unit-aware computation library for Python — built on first-principles.


Overview

ucon helps Python understand the physical meaning of your numbers. It combines units, scales, and dimensions into a composable algebra that supports:

  • Dimensional analysis through Number and Ratio
  • Scale-aware arithmetic via UnitFactor and UnitProduct
  • Metric and binary prefixes (kilo, kibi, micro, mebi, etc.)
  • Pseudo-dimensions for angles, solid angles, and ratios with semantic isolation
  • Uncertainty propagation through arithmetic and conversions
  • A clean foundation for physics, chemistry, data modeling, and beyond

Think of it as decimal.Decimal for the physical world — precise, predictable, and type-safe.

Introduction

The crux of this tiny library is to provide abstractions that simplify the answering of questions like:

"If given two milliliters of bromine (liquid Br2), how many grams of bromine does one have?"

To best answer this question, we turn to an age-old technique (dimensional analysis) which essentially allows for the solution to be written as a product of ratios. ucon comes equipped with some useful primitives:

Type Defined In Purpose Typical Use Cases
Vector ucon.algebra Represents the 8-component exponent tuple of a physical quantity's base dimensions (T, L, M, I, Θ, J, N, B). Internal representation of dimensional algebra; building derived quantities (e.g., area, velocity, force).
Exponent ucon.algebra Represents base-power pairs (e.g., 10³, 2¹⁰) used by Scale. Performing arithmetic on powers and bases; normalizing scales across conversions.
Dimension ucon.core Encapsulates physical dimensions (e.g., length, time, mass) as algebraic combinations of vectors. Enforcing dimensional consistency; defining relationships between quantities (e.g., length / time = velocity).
Scale ucon.core Encodes powers of base magnitudes (binary or decimal prefixes like kilo-, milli-, mebi-). Adjusting numeric scale without changing dimension (e.g., kilometer ↔ meter, byte ↔ kibibyte).
Unit ucon.core An atomic, scale-free measurement symbol (e.g., meter, second, joule) with a Dimension. Defining base units; serving as graph nodes for future conversions.
UnitFactor ucon.core Pairs a Unit with a Scale (e.g., kilo + gram = kg). Used as keys inside UnitProduct. Preserving user-provided scale prefixes through algebraic operations.
UnitProduct ucon.core A product/quotient of UnitFactors with exponent tracking and simplification. Representing composite units like m/s, kg·m/s², kJ·h.
Number ucon.core Combines a numeric quantity with a unit; the primary measurable type. Performing arithmetic with units; representing physical quantities like 5 m/s.
Ratio ucon.core Represents the division of two Number objects; captures relationships between quantities. Expressing rates, densities, efficiencies (e.g., energy / time = power, length / time = velocity).
Map hierarchy ucon.maps Composable conversion morphisms: LinearMap, AffineMap, ComposedMap. Defining conversion functions between units (e.g., meter→foot, celsius→kelvin).
ConversionGraph ucon.graph Registry of unit conversion edges with BFS path composition. Converting between units via Number.to(target); managing default and custom graphs.
units module ucon.units Defines canonical unit instances (SI, imperial, information, and derived units). Quick access to standard physical units (units.meter, units.foot, units.byte, etc.).

Under the Hood

ucon models unit math through a hierarchy where each layer builds on the last:

ucon Data Model

Why ucon?

Python already has mature libraries for handling units and physical quantities — Pint, SymPy, and Unum — each solving part of the same problem from different angles:

Library Focus Limitation
Pint Runtime unit conversion and compatibility checking Treats quantities as decorated numbers — conversions work, but the algebra behind them isn't inspectable or type-safe.
SymPy Symbolic algebra and simplification of unit expressions Excellent for symbolic reasoning, but not designed for runtime validation, conversion, or serialization.
Unum Unit-aware arithmetic and unit propagation Tracks units through arithmetic but lacks explicit dimensional algebra, conversion taxonomy, or runtime introspection.

Together, these tools can use units, but none can explicitly represent and verify the relationships between units and dimensions.

That's the gap ucon fills.

It treats units, dimensions, and scales as first-class objects and builds a composable algebra around them. This allows you to:

  • Represent dimensional meaning explicitly (Dimension, Vector);
  • Compose and compute with type-safe, introspectable quantities (Unit, Number);
  • Extend the system with custom unit registries and conversion families.

Where Pint, Unum, and SymPy focus on how to compute with units, ucon focuses on why those computations make sense. Every operation checks the dimensional structure, not just the unit labels. This means ucon doesn't just track names: it enforces physics:

from ucon import Number, units

length = Number(quantity=5, unit=units.meter)
time = Number(quantity=2, unit=units.second)

speed = length / time     # ✅ valid: L / T = velocity
invalid = length + time   # ❌ raises: incompatible dimensions

Setup

Simple:

pip install ucon

Usage

This sort of dimensional analysis:

 2 mL bromine | 3.119 g bromine
--------------x-----------------  #=> 6.238 g bromine
      1       |  1 mL bromine

becomes straightforward when you define a measurement:

from ucon import Number, Scale, units
from ucon.quantity import Ratio

# Two milliliters of bromine
mL = Scale.milli * units.liter
two_mL_bromine = Number(quantity=2, unit=mL)

# Density of bromine: 3.119 g/mL
bromine_density = Ratio(
    numerator=Number(unit=units.gram, quantity=3.119),
    denominator=Number(unit=mL),
)

# Multiply to find mass
grams_bromine = bromine_density.evaluate() * two_mL_bromine
print(grams_bromine)  # <6.238 g>

Scale prefixes compose naturally:

km = Scale.kilo * units.meter       # UnitProduct with kilo-scaled meter
mg = Scale.milli * units.gram       # UnitProduct with milli-scaled gram

print(km.shorthand)  # 'km'
print(mg.shorthand)  # 'mg'

# Scale arithmetic
print(km.fold_scale())  # 1000.0
print(mg.fold_scale())  # 0.001

Units are callable for ergonomic quantity construction:

from ucon import units, Scale

# Callable syntax: unit(quantity) → Number
height = units.meter(1.8)
speed = (units.mile / units.hour)(60)

# Convert between units
height_ft = height.to(units.foot)
print(height_ft)  # <5.905... ft>

# Scaled units work too
km = Scale.kilo * units.meter
distance = km(5)
distance_mi = distance.to(units.mile)
print(distance_mi)  # <3.107... mi>

Dimensionless units have semantic isolation — angles, solid angles, and ratios are distinct:

import math
from ucon import units

# Angle conversions
angle = units.radian(math.pi)
print(angle.to(units.degree))  # <180.0 deg>

# Ratio conversions
ratio = units.percent(50)
print(ratio.to(units.ppm))  # <500000.0 ppm>

# Cross-family conversions are prevented
units.radian(1).to(units.percent)  # raises ConversionNotFound

Uncertainty propagates through arithmetic and conversions:

from ucon import units

# Measurements with uncertainty
length = units.meter(1.234, uncertainty=0.005)
width = units.meter(0.567, uncertainty=0.003)

print(length)  # <1.234 ± 0.005 m>

# Uncertainty propagates through arithmetic (quadrature)
area = length * width
print(area)  # <0.699678 ± 0.00424... m²>

# Uncertainty propagates through conversion
length_ft = length.to(units.foot)
print(length_ft)  # <4.048... ± 0.0164... ft>

Roadmap Highlights

Version Theme Focus Status
0.3.x Dimensional Algebra Unit/Scale separation, UnitFactor, UnitProduct ✅ Complete
0.4.x Conversion System ConversionGraph, Number.to(), callable units ✅ Complete
0.5.0 Dimensionless Units Pseudo-dimensions for angle, solid angle, ratio ✅ Complete
0.5.x Uncertainty Propagation through arithmetic and conversions ✅ Complete
0.5.x Unit Systems BasisMap, UnitSystem 🚧 In Progress
0.7.x Pydantic Integration Type-safe quantity validation ⏳ Planned

See full roadmap: ROADMAP.md


Contributing

Contributions, issues, and pull requests are welcome! Ensure nox is installed.

pip install -r requirements.txt

Then run the full test suite (against all supported python versions) before committing:

nox -s test

"If it can be measured, it can be represented. If it can be represented, it can be validated. If it can be validated, it can be trusted."

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ucon-0.5.1.tar.gz (92.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ucon-0.5.1-py3-none-any.whl (62.3 kB view details)

Uploaded Python 3

File details

Details for the file ucon-0.5.1.tar.gz.

File metadata

  • Download URL: ucon-0.5.1.tar.gz
  • Upload date:
  • Size: 92.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ucon-0.5.1.tar.gz
Algorithm Hash digest
SHA256 b848e9670c81380d80f207c688aa74224408b8bcf04c3a374f12a6aafb28d1d3
MD5 7a3b9d737033222a8599d9107e46618d
BLAKE2b-256 afb33bb44592ca67b9cde7a5d0914ff876182f685097eaadbcba45a8f624e545

See more details on using hashes here.

File details

Details for the file ucon-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: ucon-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 62.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ucon-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 795fcb0cd78725dce8d7c7ab240d59cdc0767e76b7fbe0d7c07ea9661146ff6f
MD5 659d71209ace2c28cee098a245505fea
BLAKE2b-256 eb36fb772346849a7e348e763e76d84e5367f57c700f9f5bd9761a0213165d6c

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.5.1

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page