ucon 0.3.0__tar.gz → 0.3.1rc2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. ucon-0.3.1rc2/.github/workflows/publish.yaml +53 -0
  2. ucon-0.3.1rc2/.github/workflows/tests.yaml +51 -0
  3. ucon-0.3.1rc2/PKG-INFO +191 -0
  4. ucon-0.3.1rc2/README.md +155 -0
  5. ucon-0.3.1rc2/ROADMAP.md +222 -0
  6. ucon-0.3.1rc2/docs/assets/ucon.data-model.svg +67 -0
  7. ucon-0.3.1rc2/noxfile.py +128 -0
  8. {ucon-0.3.0 → ucon-0.3.1rc2}/setup.py +4 -0
  9. {ucon-0.3.0 → ucon-0.3.1rc2}/tests/ucon/test_core.py +92 -14
  10. {ucon-0.3.0 → ucon-0.3.1rc2}/ucon/core.py +79 -20
  11. ucon-0.3.1rc2/ucon.egg-info/PKG-INFO +191 -0
  12. {ucon-0.3.0 → ucon-0.3.1rc2}/ucon.egg-info/SOURCES.txt +2 -0
  13. ucon-0.3.0/.github/workflows/publish.yaml +0 -62
  14. ucon-0.3.0/.github/workflows/tests.yaml +0 -34
  15. ucon-0.3.0/PKG-INFO +0 -90
  16. ucon-0.3.0/README.md +0 -58
  17. ucon-0.3.0/noxfile.py +0 -114
  18. ucon-0.3.0/ucon.egg-info/PKG-INFO +0 -90
  19. {ucon-0.3.0 → ucon-0.3.1rc2}/.gitignore +0 -0
  20. {ucon-0.3.0 → ucon-0.3.1rc2}/LICENSE +0 -0
  21. {ucon-0.3.0 → ucon-0.3.1rc2}/requirements.txt +0 -0
  22. {ucon-0.3.0 → ucon-0.3.1rc2}/setup.cfg +0 -0
  23. {ucon-0.3.0 → ucon-0.3.1rc2}/tests/__init__.py +0 -0
  24. {ucon-0.3.0 → ucon-0.3.1rc2}/tests/ucon/__init__.py +0 -0
  25. {ucon-0.3.0 → ucon-0.3.1rc2}/tests/ucon/test_dimension.py +0 -0
  26. {ucon-0.3.0 → ucon-0.3.1rc2}/tests/ucon/test_unit.py +0 -0
  27. {ucon-0.3.0 → ucon-0.3.1rc2}/tests/ucon/test_units.py +0 -0
  28. {ucon-0.3.0 → ucon-0.3.1rc2}/ucon/__init__.py +0 -0
  29. {ucon-0.3.0 → ucon-0.3.1rc2}/ucon/dimension.py +0 -0
  30. {ucon-0.3.0 → ucon-0.3.1rc2}/ucon/unit.py +0 -0
  31. {ucon-0.3.0 → ucon-0.3.1rc2}/ucon/units.py +0 -0
  32. {ucon-0.3.0 → ucon-0.3.1rc2}/ucon.egg-info/dependency_links.txt +0 -0
  33. {ucon-0.3.0 → ucon-0.3.1rc2}/ucon.egg-info/top_level.txt +0 -0
@@ -0,0 +1,53 @@
1
+ name: publish
2
+
3
+ on:
4
+ push:
5
+ branches: [main] # mainline merges → Test PyPI
6
+ tags: ['*'] # tags → Test & Prod PyPI
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - name: Checkout source
14
+ uses: actions/checkout@v4
15
+ with:
16
+ fetch-depth: 0 # needed for ancestry check
17
+
18
+ - name: Set up Python
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: '3.14'
22
+
23
+ - name: Install dependencies
24
+ run: pip install -r requirements.txt
25
+
26
+ - name: Build distribution 📦
27
+ run: PYTHONWARNINGS=ignore LOCAL_VERSION_SCHEME=true nox -s build
28
+
29
+ - name: Publish to Test PyPI
30
+ if: github.ref == 'refs/heads/main'
31
+ uses: pypa/gh-action-pypi-publish@release/v1
32
+ with:
33
+ user: __token__
34
+ password: ${{ secrets.test_pypi_password }}
35
+ skip_existing: true
36
+ repository_url: https://test.pypi.org/legacy/
37
+
38
+ - name: 🧪 Publish tag build to Test PyPI
39
+ if: startsWith(github.ref, 'refs/tags/')
40
+ uses: pypa/gh-action-pypi-publish@release/v1
41
+ with:
42
+ user: __token__
43
+ password: ${{ secrets.test_pypi_password }}
44
+ skip_existing: true
45
+ repository_url: https://test.pypi.org/legacy/
46
+
47
+ - name: 🚀 Publish to Prod PyPI
48
+ if: startsWith(github.ref, 'refs/tags/')
49
+ uses: pypa/gh-action-pypi-publish@release/v1
50
+ with:
51
+ user: __token__
52
+ password: ${{ secrets.pypi_password }}
53
+ skip_existing: true
@@ -0,0 +1,51 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: ['**']
8
+
9
+ jobs:
10
+ run_tests:
11
+ runs-on: ubuntu-22.04
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version:
16
+ - '3.7'
17
+ - '3.8'
18
+ - '3.9'
19
+ - '3.10'
20
+ - '3.11'
21
+ - '3.12'
22
+ - '3.13'
23
+ - '3.14'
24
+
25
+ steps:
26
+ - name: Checkout code
27
+ uses: actions/checkout@v5
28
+
29
+ - name: Set up Python ${{ matrix.python-version }}
30
+ uses: actions/setup-python@v6
31
+ with:
32
+ python-version: ${{ matrix.python-version }}
33
+
34
+ - name: Install dependencies
35
+ run: |
36
+ python -m pip install --upgrade pip
37
+ pip install -r requirements.txt
38
+
39
+ - name: Run tests
40
+ run: nox -s test
41
+
42
+ - name: Upload coverage to Codecov
43
+ if: success() && github.repository_owner == 'withtwoemms'
44
+ run: bash <(curl -s https://codecov.io/bash) -t ${{ secrets.CODECOV_TOKEN }}
45
+
46
+ - name: Archive coverage report
47
+ if: always()
48
+ uses: actions/upload-artifact@v4
49
+ with:
50
+ name: python-${{ matrix.python-version }}-coverage-${{ github.run_id }}
51
+ path: ${{ github.workspace }}/coverage.xml
ucon-0.3.1rc2/PKG-INFO ADDED
@@ -0,0 +1,191 @@
1
+ Metadata-Version: 2.4
2
+ Name: ucon
3
+ Version: 0.3.1rc2
4
+ Summary: a tool for dimensional analysis: a "Unit CONverter"
5
+ Home-page: https://github.com/withtwoemms/ucon
6
+ Author: Emmanuel I. Obi
7
+ Maintainer: Emmanuel I. Obi
8
+ Maintainer-email: withtwoemms@gmail.com
9
+ License: MIT
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Education
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Topic :: Software Development :: Build Tools
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3.7
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Dynamic: author
27
+ Dynamic: classifier
28
+ Dynamic: description
29
+ Dynamic: description-content-type
30
+ Dynamic: home-page
31
+ Dynamic: license
32
+ Dynamic: license-file
33
+ Dynamic: maintainer
34
+ Dynamic: maintainer-email
35
+ Dynamic: summary
36
+
37
+ <img src="https://gist.githubusercontent.com/withtwoemms/0cb9e6bc8df08f326771a89eeb790f8e/raw/dde6c7d3b8a7d79eb1006ace03fb834e044cdebc/ucon-logo.png" align="left" width="420" />
38
+
39
+ # ucon
40
+
41
+ > Pronounced: _yoo · cahn_
42
+ > A lightweight, **unit-aware computation library** for Python — built on first-principles.
43
+
44
+ [![tests](https://github.com/withtwoemms/ucon/workflows/tests/badge.svg)](https://github.com/withtwoemms/ucon/actions?query=workflow%3Atests)
45
+ [![codecov](https://codecov.io/gh/withtwoemms/ucon/graph/badge.svg?token=BNONQTRJWG)](https://codecov.io/gh/withtwoemms/ucon)
46
+ [![publish](https://github.com/withtwoemms/ucon/workflows/publish/badge.svg)](https://github.com/withtwoemms/ucon/actions?query=workflow%3Apublish)
47
+
48
+ ---
49
+
50
+ ## Overview
51
+
52
+ `ucon` helps Python understand the *physical meaning* of your numbers.
53
+ It combines **units**, **scales**, and **dimensions** into a composable algebra that supports:
54
+
55
+ - Dimensional analysis through `Number` and `Ratio`
56
+ - Scale-aware arithmetic and conversions
57
+ - Metric and binary prefixes (`kilo`, `kibi`, `micro`, `mebi`, ect.)
58
+ - A clean foundation for physics, chemistry, data modeling, and beyond
59
+
60
+ Think of it as **`decimal.Decimal` for the physical world** — precise, predictable, and type-safe.
61
+
62
+ ## Introduction
63
+
64
+ The crux of this tiny library is to provide abstractions that simplify the answering of questions like:
65
+
66
+ > _"If given two milliliters of bromine (liquid Br<sub>2</sub>), how many grams of bromine does one have?"_
67
+
68
+ To best answer this question, we turn to an age-old technique ([dimensional analysis](https://en.wikipedia.org/wiki/Dimensional_analysis)) which essentially allows for the solution to be written as a product of ratios. `ucon` comes equipped with some useful primitives:
69
+ | Type | Defined In | Purpose | Typical Use Cases |
70
+ | ----------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
71
+ | **`Vector`** | `ucon.dimension` | Represents the exponent tuple of a physical quantity’s base dimensions (e.g., T, L, M, I, Θ, J, N). | Internal representation of dimensional algebra; building derived quantities (e.g., area, velocity, force). |
72
+ | **`Dimension`** | `ucon.dimension` | 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). |
73
+ | **`Unit`** | `ucon.unit` | Represents a named, dimensioned measurement unit (e.g., meter, second, joule). | Attaching human-readable units to quantities; defining or composing new units (`newton = kilogram * meter / second²`). |
74
+ | **`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). |
75
+ | **`Exponent`** | `ucon.core` | Represents base-power pairs (e.g., 10³, 2¹⁰) used by `Scale`. | Performing arithmetic on powers and bases; normalizing scales across conversions. |
76
+ | **`Number`** | `ucon.core` | Combines a numeric quantity with a unit and scale; the primary measurable type. | Performing arithmetic with units; converting between compatible units; representing physical quantities like 5 m/s. |
77
+ | **`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). |
78
+ | **`units` module** | `ucon.units` | Defines canonical unit instances (SI and common derived units). | Quick access to standard physical units (`units.meter`, `units.second`, `units.newton`, etc.). | |
79
+
80
+ ### Under the Hood
81
+
82
+ `ucon` models unit math through a hierarchy where each layer builds on the last:
83
+
84
+ ![Alt text](./docs/assets/ucon.data-model.svg "Data Model Diagram")
85
+
86
+ ## Why `ucon`?
87
+
88
+ 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:
89
+
90
+ | Library | Focus | Limitation |
91
+ | --------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
92
+ | **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. |
93
+ | **SymPy** | Symbolic algebra and simplification of unit expressions | Excellent for symbolic reasoning, but not designed for runtime validation, conversion, or serialization. |
94
+ | **Unum** | Unit-aware arithmetic and unit propagation | Tracks units through arithmetic but lacks explicit dimensional algebra, conversion taxonomy, or runtime introspection. |
95
+
96
+ Together, these tools can _use_ units, but none can explicitly represent and verify the relationships between units and dimensions.
97
+
98
+ That’s the gap `ucon` fills.
99
+
100
+ It treats units, dimensions, and scales as first-class objects and builds a composable algebra around them.
101
+ This allows you to:
102
+ - Represent dimensional meaning explicitly (`Dimension`, `Vector`);
103
+ - Compose and compute with type-safe, introspectable quantities (`Unit`, `Number`);
104
+ - Perform reversible, declarative conversions (standard, linear, affine, nonlinear);
105
+ - Serialize and validate measurements with Pydantic integration;
106
+ - Extend the system with custom unit registries and conversion families.
107
+
108
+ Where Pint, Unum, and SymPy focus on _how_ to compute with units,
109
+ `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:
110
+ ```python
111
+ from ucon import Number, units
112
+
113
+ length = Number(quantity=5, unit=units.meter)
114
+ time = Number(quantity=2, unit=units.second)
115
+
116
+ speed = length / time # ✅ valid: L / T = velocity
117
+ invalid = length + time # ❌ raises: incompatible dimensions
118
+ ```
119
+
120
+ ## Setup
121
+
122
+ Simple:
123
+ ```bash
124
+ pip install ucon
125
+ ```
126
+
127
+ ## Usage
128
+
129
+ This sort of dimensional analysis:
130
+ ```
131
+ 2 mL bromine | 3.119 g bromine
132
+ --------------x----------------- #=> 6.238 g bromine
133
+ 1 | 1 mL bromine
134
+ ```
135
+ becomes straightforward when you define a measurement:
136
+ ```python
137
+ from ucon import Number, Scale, Units, Ratio
138
+
139
+ # Two milliliters of bromine
140
+ two_mL_bromine = Number(unit=Units.liter, scale=Scale.milli, quantity=2)
141
+
142
+ # Density of bromine: 3.119 g/mL
143
+ bromine_density = Ratio(
144
+ numerator=Number(unit=Units.gram, quantity=3.119),
145
+ denominator=Number(unit=Units.liter, scale=Scale.milli),
146
+ )
147
+
148
+ # Multiply to find mass
149
+ grams_bromine = two_mL_bromine * bromine_density
150
+ print(grams_bromine) # <6.238 gram>
151
+ ```
152
+
153
+ Scale conversion is automatic and precise:
154
+
155
+ ```python
156
+ grams_bromine.to(Scale.milli) # <6238.0 milligram>
157
+ grams_bromine.to(Scale.kibi) # <0.006091796875 kibigram>
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Roadmap Highlights
163
+
164
+ | Version | Theme | Focus |
165
+ |----------|-------|--------|
166
+ | [**0.3.x**](https://github.com/withtwoemms/ucon/milestone/1) | Primitive Type Refinement | Unified algebraic foundation |
167
+ | [**0.4.x**](https://github.com/withtwoemms/ucon/milestone/2) | Conversion System | Linear & affine conversions |
168
+ | [**0.6.x**](https://github.com/withtwoemms/ucon/milestone/4) | Nonlinear / Specialized Units | Decibel, Percent, pH |
169
+ | [**0.8.x**](https://github.com/withtwoemms/ucon/milestone/6) | Pydantic Integration | Type-safe quantity validation |
170
+
171
+ See full roadmap: [ROADMAP.md](./ROADMAP.md)
172
+
173
+ ---
174
+
175
+ ## Contributing
176
+
177
+ Contributions, issues, and pull requests are welcome!
178
+ Ensure `nox` is installed.
179
+ ```
180
+ pip install -r requirements.txt
181
+ ```
182
+ Then run the full test suite (agains all supported python versions) before committing:
183
+
184
+ ```bash
185
+ nox -s test
186
+ ```
187
+ ---
188
+
189
+ > “If it can be measured, it can be represented.
190
+ If it can be represented, it can be validated.
191
+ If it can be validated, it can be trusted.”
@@ -0,0 +1,155 @@
1
+ <img src="https://gist.githubusercontent.com/withtwoemms/0cb9e6bc8df08f326771a89eeb790f8e/raw/dde6c7d3b8a7d79eb1006ace03fb834e044cdebc/ucon-logo.png" align="left" width="420" />
2
+
3
+ # ucon
4
+
5
+ > Pronounced: _yoo · cahn_
6
+ > A lightweight, **unit-aware computation library** for Python — built on first-principles.
7
+
8
+ [![tests](https://github.com/withtwoemms/ucon/workflows/tests/badge.svg)](https://github.com/withtwoemms/ucon/actions?query=workflow%3Atests)
9
+ [![codecov](https://codecov.io/gh/withtwoemms/ucon/graph/badge.svg?token=BNONQTRJWG)](https://codecov.io/gh/withtwoemms/ucon)
10
+ [![publish](https://github.com/withtwoemms/ucon/workflows/publish/badge.svg)](https://github.com/withtwoemms/ucon/actions?query=workflow%3Apublish)
11
+
12
+ ---
13
+
14
+ ## Overview
15
+
16
+ `ucon` helps Python understand the *physical meaning* of your numbers.
17
+ It combines **units**, **scales**, and **dimensions** into a composable algebra that supports:
18
+
19
+ - Dimensional analysis through `Number` and `Ratio`
20
+ - Scale-aware arithmetic and conversions
21
+ - Metric and binary prefixes (`kilo`, `kibi`, `micro`, `mebi`, ect.)
22
+ - A clean foundation for physics, chemistry, data modeling, and beyond
23
+
24
+ Think of it as **`decimal.Decimal` for the physical world** — precise, predictable, and type-safe.
25
+
26
+ ## Introduction
27
+
28
+ The crux of this tiny library is to provide abstractions that simplify the answering of questions like:
29
+
30
+ > _"If given two milliliters of bromine (liquid Br<sub>2</sub>), how many grams of bromine does one have?"_
31
+
32
+ To best answer this question, we turn to an age-old technique ([dimensional analysis](https://en.wikipedia.org/wiki/Dimensional_analysis)) which essentially allows for the solution to be written as a product of ratios. `ucon` comes equipped with some useful primitives:
33
+ | Type | Defined In | Purpose | Typical Use Cases |
34
+ | ----------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
35
+ | **`Vector`** | `ucon.dimension` | Represents the exponent tuple of a physical quantity’s base dimensions (e.g., T, L, M, I, Θ, J, N). | Internal representation of dimensional algebra; building derived quantities (e.g., area, velocity, force). |
36
+ | **`Dimension`** | `ucon.dimension` | 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). |
37
+ | **`Unit`** | `ucon.unit` | Represents a named, dimensioned measurement unit (e.g., meter, second, joule). | Attaching human-readable units to quantities; defining or composing new units (`newton = kilogram * meter / second²`). |
38
+ | **`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). |
39
+ | **`Exponent`** | `ucon.core` | Represents base-power pairs (e.g., 10³, 2¹⁰) used by `Scale`. | Performing arithmetic on powers and bases; normalizing scales across conversions. |
40
+ | **`Number`** | `ucon.core` | Combines a numeric quantity with a unit and scale; the primary measurable type. | Performing arithmetic with units; converting between compatible units; representing physical quantities like 5 m/s. |
41
+ | **`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). |
42
+ | **`units` module** | `ucon.units` | Defines canonical unit instances (SI and common derived units). | Quick access to standard physical units (`units.meter`, `units.second`, `units.newton`, etc.). | |
43
+
44
+ ### Under the Hood
45
+
46
+ `ucon` models unit math through a hierarchy where each layer builds on the last:
47
+
48
+ ![Alt text](./docs/assets/ucon.data-model.svg "Data Model Diagram")
49
+
50
+ ## Why `ucon`?
51
+
52
+ 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:
53
+
54
+ | Library | Focus | Limitation |
55
+ | --------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
56
+ | **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. |
57
+ | **SymPy** | Symbolic algebra and simplification of unit expressions | Excellent for symbolic reasoning, but not designed for runtime validation, conversion, or serialization. |
58
+ | **Unum** | Unit-aware arithmetic and unit propagation | Tracks units through arithmetic but lacks explicit dimensional algebra, conversion taxonomy, or runtime introspection. |
59
+
60
+ Together, these tools can _use_ units, but none can explicitly represent and verify the relationships between units and dimensions.
61
+
62
+ That’s the gap `ucon` fills.
63
+
64
+ It treats units, dimensions, and scales as first-class objects and builds a composable algebra around them.
65
+ This allows you to:
66
+ - Represent dimensional meaning explicitly (`Dimension`, `Vector`);
67
+ - Compose and compute with type-safe, introspectable quantities (`Unit`, `Number`);
68
+ - Perform reversible, declarative conversions (standard, linear, affine, nonlinear);
69
+ - Serialize and validate measurements with Pydantic integration;
70
+ - Extend the system with custom unit registries and conversion families.
71
+
72
+ Where Pint, Unum, and SymPy focus on _how_ to compute with units,
73
+ `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:
74
+ ```python
75
+ from ucon import Number, units
76
+
77
+ length = Number(quantity=5, unit=units.meter)
78
+ time = Number(quantity=2, unit=units.second)
79
+
80
+ speed = length / time # ✅ valid: L / T = velocity
81
+ invalid = length + time # ❌ raises: incompatible dimensions
82
+ ```
83
+
84
+ ## Setup
85
+
86
+ Simple:
87
+ ```bash
88
+ pip install ucon
89
+ ```
90
+
91
+ ## Usage
92
+
93
+ This sort of dimensional analysis:
94
+ ```
95
+ 2 mL bromine | 3.119 g bromine
96
+ --------------x----------------- #=> 6.238 g bromine
97
+ 1 | 1 mL bromine
98
+ ```
99
+ becomes straightforward when you define a measurement:
100
+ ```python
101
+ from ucon import Number, Scale, Units, Ratio
102
+
103
+ # Two milliliters of bromine
104
+ two_mL_bromine = Number(unit=Units.liter, scale=Scale.milli, quantity=2)
105
+
106
+ # Density of bromine: 3.119 g/mL
107
+ bromine_density = Ratio(
108
+ numerator=Number(unit=Units.gram, quantity=3.119),
109
+ denominator=Number(unit=Units.liter, scale=Scale.milli),
110
+ )
111
+
112
+ # Multiply to find mass
113
+ grams_bromine = two_mL_bromine * bromine_density
114
+ print(grams_bromine) # <6.238 gram>
115
+ ```
116
+
117
+ Scale conversion is automatic and precise:
118
+
119
+ ```python
120
+ grams_bromine.to(Scale.milli) # <6238.0 milligram>
121
+ grams_bromine.to(Scale.kibi) # <0.006091796875 kibigram>
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Roadmap Highlights
127
+
128
+ | Version | Theme | Focus |
129
+ |----------|-------|--------|
130
+ | [**0.3.x**](https://github.com/withtwoemms/ucon/milestone/1) | Primitive Type Refinement | Unified algebraic foundation |
131
+ | [**0.4.x**](https://github.com/withtwoemms/ucon/milestone/2) | Conversion System | Linear & affine conversions |
132
+ | [**0.6.x**](https://github.com/withtwoemms/ucon/milestone/4) | Nonlinear / Specialized Units | Decibel, Percent, pH |
133
+ | [**0.8.x**](https://github.com/withtwoemms/ucon/milestone/6) | Pydantic Integration | Type-safe quantity validation |
134
+
135
+ See full roadmap: [ROADMAP.md](./ROADMAP.md)
136
+
137
+ ---
138
+
139
+ ## Contributing
140
+
141
+ Contributions, issues, and pull requests are welcome!
142
+ Ensure `nox` is installed.
143
+ ```
144
+ pip install -r requirements.txt
145
+ ```
146
+ Then run the full test suite (agains all supported python versions) before committing:
147
+
148
+ ```bash
149
+ nox -s test
150
+ ```
151
+ ---
152
+
153
+ > “If it can be measured, it can be represented.
154
+ If it can be represented, it can be validated.
155
+ If it can be validated, it can be trusted.”
@@ -0,0 +1,222 @@
1
+ # 🧭 ucon Roadmap
2
+
3
+ > *A clear path from algebraic foundation to a stable 1.0 release.*
4
+
5
+ ---
6
+
7
+ ## 🪜 Current Version: **v0.3.0**
8
+
9
+ Stable baseline for:
10
+ - `ucon.core` (`Number`, `Scale`, `Ratio`)
11
+ - `ucon.unit` (basic unit representation and composition)
12
+ - `ucon.units` (canonical SI definitions)
13
+ - Initial CI, testing, and packaging
14
+
15
+ ---
16
+
17
+ ## 🚀 v0.3.x — Dimensional Algebra (In Progress)
18
+
19
+ ### 🔹 Summary
20
+ > Introduces `ucon.dimension` as the foundation for algebraic reasoning.
21
+
22
+ ### ✅ Goals
23
+ - [x] Implement `Vector` and `Dimension` classes
24
+ - [x] Integrate dimensions into `Unit`
25
+ - [x] Refactor `ucon.units` to use dimensional definitions
26
+ - [ ] Publish documentation for dimensional operations
27
+ - [x] Verify uniqueness and hashing correctness across all Dimensions
28
+ - [ ] Redesign `Exponent` to support algebraic operations (`__mul__`, `__truediv__`, `to_base`, etc.)
29
+ - [ ] Remove redundant evaluated caching in favor of property-based computation
30
+ - [ ] Integrate `Scale` with Exponent for consistent prefix arithmetic
31
+ - [ ] Update `Number` and `Ratio` to use Exponent-driven scaling
32
+ - [ ] Add regression tests for prefix math (`kilo / milli → mega`, `2¹⁰ / 10³ → 1.024×`)
33
+ - [ ] Document Exponent/Scale relationship in developer guide
34
+
35
+ ### 🧩 Outcomes
36
+ - All units acquire explicit dimensional semantics
37
+ - Enables composable and type-safe dimensional operations
38
+ - Establishes the mathematical foundation for future conversions
39
+ - Unified algebraic foundation for all scaling and magnitude operations
40
+ - Precise, reversible cross-base math (`2ⁿ ↔ 10ᵐ`)
41
+ - Simplified, consistent `Scale` and `Number` behavior
42
+ - Ready for integration into the conversion engine (`ucon.conversions`)
43
+
44
+ ---
45
+
46
+ ## ⚙️ v0.4.x — Conversion System Foundations
47
+
48
+ ### 🔹 Summary
49
+ > Implements unified conversion engine for standard, linear, and affine conversions.
50
+
51
+ ### ✅ Goals
52
+ - [ ] Introduce `ucon.conversions` registry keyed by `Dimension`
53
+ - [ ] Add support for `standard`, `linear`, and `affine` conversion types
54
+ - [ ] Implement `.to(target_unit)` for `Number`
55
+ - [ ] Round-trip validation for reversible conversions
56
+ - [ ] Extend tests to include temperature, pressure, and base SI conversions
57
+
58
+ ### 🧩 Outcomes
59
+ - Unified conversion taxonomy
60
+ - Reversible, dimension-checked conversions
61
+ - Forms the basis for nonlinear and domain-specific conversion families
62
+
63
+ ---
64
+
65
+ ## 🧱 v0.5.x — Unit Systems & Registries
66
+
67
+ ### 🔹 Summary
68
+ > Introduces an extensible registry system for custom units and aliases.
69
+
70
+ ### ✅ Goals
71
+ - [x] Implement `have(name)` membership check
72
+ - [ ] Add `UnitSystem` abstraction
73
+ - [ ] Support `registry.add(unit)` and dynamic system registration
74
+ - [ ] Validate alias uniqueness and collision prevention
75
+ - [ ] Include examples for user-defined unit extensions
76
+
77
+ ### 🧩 Outcomes
78
+ - Registry-based extensibility for domain-specific systems
79
+ - Dynamic unit registration and discovery
80
+ - Groundwork for plugin-style system extensions
81
+
82
+ ---
83
+
84
+ ## 🧪 v0.6.x — Nonlinear & Specialized Conversions
85
+
86
+ ### 🔹 Summary
87
+ > Adds support for logarithmic, fractional, and other specialized dimensionless conversions.
88
+
89
+ ### ✅ Goals
90
+ - [ ] Extend conversion registry schema with `"nonlinear"` family
91
+ - [ ] Add `to_base` / `from_base` lambdas for function-based mappings
92
+ - [ ] Define sample nonlinear conversions (`decibel`, `bel`, `pH`)
93
+ - [ ] Add tolerance-aware tests for nonlinear conversions
94
+ - [ ] Introduce structured dimensionless unit family (`radian`, `percent`, `ppm`, `count`, etc.)
95
+ - [ ] Define canonical dimensionless subtypes for angular, fractional, and count semantics
96
+ - [ ] Ensure automatic collapse of equivalent units (`m/m → none`, `J/J → none`) via Ratio
97
+
98
+ ### 🧩 Outcomes
99
+ - Support for function-based (nonlinear) physical conversions
100
+ - Unified algebraic framework across all conversion types
101
+ - Rich, semantically meaningful representation of dimensionless quantities
102
+ - Enables acoustics (dB), geometry (rad, sr), statistics (probability), and fractional scales (%, ppm)
103
+
104
+ ---
105
+
106
+ ## 🧰 v0.7.x — Testing, Developer Experience, & API Polish
107
+
108
+ ### 🔹 Summary
109
+ > Strengthens tests, developer ergonomics, and runtime feedback.
110
+
111
+ ### ✅ Goals
112
+ - [ ] Reach 95%+ test coverage
113
+ - [ ] Add property-based tests for dimensional invariants
114
+ - [ ] Improve error reporting, `__repr__`, and exception messaging
115
+ - [ ] Validate public API imports and maintain consistent naming
116
+ - [ ] Add CI coverage reports and build badges
117
+
118
+ ### 🧩 Outcomes
119
+ - Reliable, developer-friendly foundation
120
+ - Consistent runtime behavior and output clarity
121
+ - Prepares API for public documentation and 1.0 freeze
122
+
123
+ ---
124
+
125
+ ## 🧩 v0.8.x — Pydantic Integration
126
+
127
+ ### 🔹 Summary
128
+ > Introduces seamless integration with **Pydantic v2**, enabling validation, serialization, and typed dimensional models.
129
+
130
+ ### ✅ Goals
131
+ - [ ] Define Pydantic-compatible field types (`UnitType`, `NumberType`)
132
+ - [ ] Implement `__get_pydantic_core_schema__` for Units and Numbers
133
+ - [ ] Support automatic conversion/validation for user-defined models
134
+ - [ ] Add YAML / JSON encoding for quantities (`Number(unit="meter", quantity=5)`)
135
+ - [ ] Add Pydantic-based examples (API config, simulation parameters)
136
+
137
+ ### 🧩 Outcomes
138
+ - Native validation and serialization for dimensioned quantities
139
+ - Enables safe configuration in data models and APIs
140
+ - Bridges `ucon`’s algebraic model with modern Python typing ecosystems
141
+
142
+ ---
143
+
144
+ ## 📘 v0.9.x — Documentation & RC Phase
145
+
146
+ ### 🔹 Summary
147
+ > Completes documentation, finalizes examples, and preps release candidates.
148
+
149
+ ### ✅ Goals
150
+ - [ ] Write comprehensive README and developer guide
151
+ - [ ] Publish API reference docs (Sphinx / MkDocs)
152
+ - [ ] Add SymPy / Pint comparison appendix
153
+ - [ ] Freeze and document all public APIs
154
+ - [ ] Publish one or more release candidates (RC1, RC2)
155
+
156
+ ### 🧩 Outcomes
157
+ - Complete public-facing documentation
158
+ - API frozen and versioned for stability
159
+ - Ready for final testing and validation before 1.0
160
+
161
+ ---
162
+
163
+ ## 🏁 v1.0.0 — Stable, Introspective Core
164
+
165
+ ### 🔹 Summary
166
+ > First major release: a unified algebra for composable, type-safe, and semantically clear unit conversion.
167
+
168
+ ### ✅ Goals
169
+ - [ ] Tag and release to PyPI
170
+ - [ ] Validate packaging and dependency metadata
171
+ - [ ] Include examples and tutorials in docs
172
+ - [ ] Announce 1.0 on GitHub and PyPI
173
+
174
+ ### 🧩 Outcomes
175
+ - Stable, well-tested release
176
+ - Fully type-safe and validated core
177
+ - Production-ready for integration into scientific and engineering workflows
178
+
179
+ ---
180
+
181
+ ## 🧠 Post-1.0 Vision
182
+
183
+ | Future Direction | Description |
184
+ |------------------|-------------|
185
+ | **Graph-based conversion paths** | Automatically discover multi-hop conversions between compatible units |
186
+ | **Type-safe generics** | `Number[Dimension.length]` support for type checking and IDE hints |
187
+ | **Symbolic bridge to SymPy** | Export units and expressions for symbolic manipulation |
188
+ | **Visualization** | Dimensional relationship graphs and dependency trees |
189
+ | **Plugin architecture** | Load conversions and systems dynamically (YAML/JSON plugins) |
190
+
191
+ ---
192
+
193
+ ## 🗓️ Milestone Summary
194
+
195
+ | Version | Theme | Key Focus | Target | Status |
196
+ |----------|--------|------------|---------|---------|
197
+ | **0.3.0** | Dimensional Algebra | Introduce `ucon.dimension` | **Nov 2025** | 🚧 In Progress |
198
+ | **0.4.0** | Conversion Engine | Standard, linear, affine conversions | **Jan 2026** | ⏳ Planned |
199
+ | **0.5.0** | Unit Systems & Registries | Extensible registry system | **Mar 2026** | ⏳ Planned |
200
+ | **0.6.0** | Nonlinear Conversions | Logarithmic / exponential families | **May 2026** | ⏳ Planned |
201
+ | **0.7.0** | Testing & API Polish | Coverage, ergonomics, stability | **Jul 2026** | ⏳ Planned |
202
+ | **0.8.0** | 🧩 **Pydantic Integration** | Typed validation, serialization | **Sep 2026** | 🧭 Newly Added |
203
+ | **0.9.x** | Documentation & RC | Freeze API, publish docs, RCs | **Nov 2026** | ⏳ Planned |
204
+ | **1.0.0** | Stable Release | Publish production-ready core | **Jan 2027** | 🔮 Future |
205
+
206
+ ---
207
+
208
+ ### ✨ Guiding Principle
209
+
210
+ > “If it can be measured, it can be represented.
211
+ > If it can be represented, it can be validated.
212
+ > If it can be validated, it can be trusted.”
213
+
214
+ ---
215
+
216
+ ### 💡 Why Pydantic Integration Matters
217
+
218
+ - Enables **runtime validation** of dimensional correctness:
219
+ ```python
220
+ class Config(BaseModel):
221
+ length: NumberType[Dimension.length]
222
+ time: NumberType[Dimension.time]