ucon 0.6.0__py3-none-any.whl → 0.6.2__py3-none-any.whl
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.
- ucon/graph.py +8 -6
- ucon/maps.py +116 -0
- ucon/units.py +20 -3
- {ucon-0.6.0.dist-info → ucon-0.6.2.dist-info}/METADATA +48 -3
- ucon-0.6.2.dist-info/RECORD +17 -0
- ucon-0.6.0.dist-info/RECORD +0 -17
- {ucon-0.6.0.dist-info → ucon-0.6.2.dist-info}/WHEEL +0 -0
- {ucon-0.6.0.dist-info → ucon-0.6.2.dist-info}/entry_points.txt +0 -0
- {ucon-0.6.0.dist-info → ucon-0.6.2.dist-info}/licenses/LICENSE +0 -0
- {ucon-0.6.0.dist-info → ucon-0.6.2.dist-info}/licenses/NOTICE +0 -0
- {ucon-0.6.0.dist-info → ucon-0.6.2.dist-info}/top_level.txt +0 -0
ucon/graph.py
CHANGED
|
@@ -37,7 +37,7 @@ from ucon.core import (
|
|
|
37
37
|
UnitProduct,
|
|
38
38
|
Scale,
|
|
39
39
|
)
|
|
40
|
-
from ucon.maps import Map, LinearMap, AffineMap
|
|
40
|
+
from ucon.maps import Map, LinearMap, AffineMap, LogMap
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
class DimensionMismatch(Exception):
|
|
@@ -589,10 +589,12 @@ def _build_standard_graph() -> ConversionGraph:
|
|
|
589
589
|
graph.add_edge(src=units.steradian, dst=units.square_degree, map=LinearMap((180 / math.pi) ** 2))
|
|
590
590
|
|
|
591
591
|
# --- Ratio ---
|
|
592
|
-
graph.add_edge(src=units.
|
|
593
|
-
graph.add_edge(src=units.
|
|
594
|
-
graph.add_edge(src=units.
|
|
595
|
-
graph.add_edge(src=units.
|
|
596
|
-
graph.add_edge(src=units.
|
|
592
|
+
graph.add_edge(src=units.fraction, dst=units.percent, map=LinearMap(100))
|
|
593
|
+
graph.add_edge(src=units.fraction, dst=units.permille, map=LinearMap(1000))
|
|
594
|
+
graph.add_edge(src=units.fraction, dst=units.ppm, map=LinearMap(1e6))
|
|
595
|
+
graph.add_edge(src=units.fraction, dst=units.ppb, map=LinearMap(1e9))
|
|
596
|
+
graph.add_edge(src=units.fraction, dst=units.basis_point, map=LinearMap(10000))
|
|
597
|
+
# nines: -log₁₀(1 - availability) for SRE uptime (0.99999 → 5 nines)
|
|
598
|
+
graph.add_edge(src=units.fraction, dst=units.nines, map=LogMap(scale=-1) @ AffineMap(a=-1, b=1))
|
|
597
599
|
|
|
598
600
|
return graph
|
ucon/maps.py
CHANGED
|
@@ -14,10 +14,13 @@ Classes
|
|
|
14
14
|
- :class:`Map` — Abstract base for conversion morphisms.
|
|
15
15
|
- :class:`LinearMap` — y = a * x
|
|
16
16
|
- :class:`AffineMap` — y = a * x + b
|
|
17
|
+
- :class:`LogMap` — y = scale * log_base(x) + offset
|
|
18
|
+
- :class:`ExpMap` — y = base^(scale * x + offset)
|
|
17
19
|
- :class:`ComposedMap` — Generic composition fallback: g(f(x))
|
|
18
20
|
"""
|
|
19
21
|
from __future__ import annotations
|
|
20
22
|
|
|
23
|
+
import math
|
|
21
24
|
from abc import ABC, abstractmethod
|
|
22
25
|
from dataclasses import dataclass
|
|
23
26
|
|
|
@@ -145,6 +148,119 @@ class AffineMap(Map):
|
|
|
145
148
|
return self.a
|
|
146
149
|
|
|
147
150
|
|
|
151
|
+
@dataclass(frozen=True)
|
|
152
|
+
class LogMap(Map):
|
|
153
|
+
"""
|
|
154
|
+
Logarithmic map: ``y = scale * log_base(x) + offset``
|
|
155
|
+
|
|
156
|
+
Examples::
|
|
157
|
+
|
|
158
|
+
LogMap() # log₁₀(x)
|
|
159
|
+
LogMap(scale=10) # 10·log₁₀(x) — decibels (power)
|
|
160
|
+
LogMap(scale=20) # 20·log₁₀(x) — decibels (amplitude)
|
|
161
|
+
LogMap(scale=-1) # -log₁₀(x) — pH-style
|
|
162
|
+
LogMap(base=math.e) # ln(x) — neper
|
|
163
|
+
|
|
164
|
+
For transforms like nines ``(-log₁₀(1-x))``, compose with AffineMap::
|
|
165
|
+
|
|
166
|
+
LogMap(scale=-1) @ AffineMap(a=-1, b=1)
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
scale: float = 1.0
|
|
170
|
+
base: float = 10.0
|
|
171
|
+
offset: float = 0.0
|
|
172
|
+
|
|
173
|
+
def __call__(self, x: float) -> float:
|
|
174
|
+
if x <= 0:
|
|
175
|
+
raise ValueError(f"Logarithm argument must be positive, got {x}")
|
|
176
|
+
return self.scale * math.log(x, self.base) + self.offset
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def invertible(self) -> bool:
|
|
180
|
+
return self.scale != 0
|
|
181
|
+
|
|
182
|
+
def inverse(self) -> 'ExpMap':
|
|
183
|
+
"""Return the inverse exponential map."""
|
|
184
|
+
if not self.invertible:
|
|
185
|
+
raise ZeroDivisionError("LogMap with scale=0 is not invertible.")
|
|
186
|
+
return ExpMap(
|
|
187
|
+
scale=1.0 / self.scale,
|
|
188
|
+
base=self.base,
|
|
189
|
+
offset=-self.offset / self.scale,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
def __matmul__(self, other: Map) -> Map:
|
|
193
|
+
if not isinstance(other, Map):
|
|
194
|
+
return NotImplemented
|
|
195
|
+
return ComposedMap(self, other)
|
|
196
|
+
|
|
197
|
+
def __pow__(self, exp: float) -> Map:
|
|
198
|
+
if exp == 1:
|
|
199
|
+
return self
|
|
200
|
+
if exp == -1:
|
|
201
|
+
return self.inverse()
|
|
202
|
+
raise ValueError("LogMap only supports exp=1 or exp=-1")
|
|
203
|
+
|
|
204
|
+
def derivative(self, x: float) -> float:
|
|
205
|
+
"""Derivative: d/dx[scale * log_base(x) + offset] = scale / (x * ln(base))"""
|
|
206
|
+
if x <= 0:
|
|
207
|
+
raise ValueError(f"Derivative undefined for x={x}")
|
|
208
|
+
return self.scale / (x * math.log(self.base))
|
|
209
|
+
|
|
210
|
+
def is_identity(self, tol: float = 1e-9) -> bool:
|
|
211
|
+
return False # Logarithm is never identity
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@dataclass(frozen=True)
|
|
215
|
+
class ExpMap(Map):
|
|
216
|
+
"""
|
|
217
|
+
Exponential map: ``y = base^(scale * x + offset)``
|
|
218
|
+
|
|
219
|
+
This is the inverse of :class:`LogMap`. Typically obtained via
|
|
220
|
+
``LogMap.inverse()`` rather than constructed directly.
|
|
221
|
+
"""
|
|
222
|
+
|
|
223
|
+
scale: float = 1.0
|
|
224
|
+
base: float = 10.0
|
|
225
|
+
offset: float = 0.0
|
|
226
|
+
|
|
227
|
+
def __call__(self, x: float) -> float:
|
|
228
|
+
return self.base ** (self.scale * x + self.offset)
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def invertible(self) -> bool:
|
|
232
|
+
return self.scale != 0
|
|
233
|
+
|
|
234
|
+
def inverse(self) -> LogMap:
|
|
235
|
+
"""Return the inverse logarithmic map."""
|
|
236
|
+
if not self.invertible:
|
|
237
|
+
raise ZeroDivisionError("ExpMap with scale=0 is not invertible.")
|
|
238
|
+
return LogMap(
|
|
239
|
+
scale=1.0 / self.scale,
|
|
240
|
+
base=self.base,
|
|
241
|
+
offset=-self.offset / self.scale,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
def __matmul__(self, other: Map) -> Map:
|
|
245
|
+
if not isinstance(other, Map):
|
|
246
|
+
return NotImplemented
|
|
247
|
+
return ComposedMap(self, other)
|
|
248
|
+
|
|
249
|
+
def __pow__(self, exp: float) -> Map:
|
|
250
|
+
if exp == 1:
|
|
251
|
+
return self
|
|
252
|
+
if exp == -1:
|
|
253
|
+
return self.inverse()
|
|
254
|
+
raise ValueError("ExpMap only supports exp=1 or exp=-1")
|
|
255
|
+
|
|
256
|
+
def derivative(self, x: float) -> float:
|
|
257
|
+
"""Derivative: d/dx[base^(scale*x + offset)] = ln(base) * scale * base^(scale*x + offset)"""
|
|
258
|
+
return math.log(self.base) * self.scale * self(x)
|
|
259
|
+
|
|
260
|
+
def is_identity(self, tol: float = 1e-9) -> bool:
|
|
261
|
+
return False # Exponential is never identity
|
|
262
|
+
|
|
263
|
+
|
|
148
264
|
@dataclass(frozen=True)
|
|
149
265
|
class ComposedMap(Map):
|
|
150
266
|
"""Generic composition fallback: ``(outer ∘ inner)(x) = outer(inner(x))``."""
|
ucon/units.py
CHANGED
|
@@ -140,12 +140,13 @@ square_degree = Unit(name='square_degree', dimension=Dimension.solid_angle, alia
|
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
# -- Ratio Units -------------------------------------------------------
|
|
143
|
-
|
|
143
|
+
fraction = Unit(name='fraction', dimension=Dimension.ratio, aliases=('frac', '1'))
|
|
144
144
|
percent = Unit(name='percent', dimension=Dimension.ratio, aliases=('%',))
|
|
145
145
|
permille = Unit(name='permille', dimension=Dimension.ratio, aliases=('‰',))
|
|
146
146
|
ppm = Unit(name='ppm', dimension=Dimension.ratio, aliases=())
|
|
147
147
|
ppb = Unit(name='ppb', dimension=Dimension.ratio, aliases=())
|
|
148
148
|
basis_point = Unit(name='basis_point', dimension=Dimension.ratio, aliases=('bp', 'bps'))
|
|
149
|
+
nines = Unit(name='nines', dimension=Dimension.ratio, aliases=('9s',))
|
|
149
150
|
# ----------------------------------------------------------------------
|
|
150
151
|
|
|
151
152
|
|
|
@@ -203,6 +204,10 @@ def have(name: str) -> bool:
|
|
|
203
204
|
_UNIT_REGISTRY: Dict[str, Unit] = {}
|
|
204
205
|
_UNIT_REGISTRY_CASE_SENSITIVE: Dict[str, Unit] = {}
|
|
205
206
|
|
|
207
|
+
# Priority aliases that must match exactly before prefix decomposition.
|
|
208
|
+
# Prevents ambiguous parses like "min" -> milli-inch instead of minute.
|
|
209
|
+
_PRIORITY_ALIASES: set = {'min'}
|
|
210
|
+
|
|
206
211
|
# Scale prefix mapping (shorthand -> Scale)
|
|
207
212
|
# Sorted by length descending for greedy matching
|
|
208
213
|
_SCALE_PREFIXES: Dict[str, Scale] = {
|
|
@@ -293,7 +298,10 @@ def _lookup_factor(s: str) -> Tuple[Unit, Scale]:
|
|
|
293
298
|
"""
|
|
294
299
|
Look up a single unit factor, handling scale prefixes.
|
|
295
300
|
|
|
296
|
-
Prioritizes prefix+unit interpretation over direct unit lookup
|
|
301
|
+
Prioritizes prefix+unit interpretation over direct unit lookup,
|
|
302
|
+
except for priority aliases (like 'min') which are checked first
|
|
303
|
+
to avoid ambiguous parses.
|
|
304
|
+
|
|
297
305
|
This means "kg" returns (gram, Scale.kilo) rather than (kilogram, Scale.one).
|
|
298
306
|
|
|
299
307
|
Examples:
|
|
@@ -302,6 +310,7 @@ def _lookup_factor(s: str) -> Tuple[Unit, Scale]:
|
|
|
302
310
|
- 'km' -> (meter, Scale.kilo)
|
|
303
311
|
- 'kg' -> (gram, Scale.kilo)
|
|
304
312
|
- 'mL' -> (liter, Scale.milli)
|
|
313
|
+
- 'min' -> (minute, Scale.one) # priority alias, not milli-inch
|
|
305
314
|
|
|
306
315
|
Returns:
|
|
307
316
|
Tuple of (unit, scale).
|
|
@@ -309,7 +318,15 @@ def _lookup_factor(s: str) -> Tuple[Unit, Scale]:
|
|
|
309
318
|
Raises:
|
|
310
319
|
UnknownUnitError: If the unit cannot be resolved.
|
|
311
320
|
"""
|
|
312
|
-
#
|
|
321
|
+
# Check priority aliases first (prevents "min" -> milli-inch)
|
|
322
|
+
if s in _PRIORITY_ALIASES:
|
|
323
|
+
if s in _UNIT_REGISTRY_CASE_SENSITIVE:
|
|
324
|
+
return _UNIT_REGISTRY_CASE_SENSITIVE[s], Scale.one
|
|
325
|
+
s_lower = s.lower()
|
|
326
|
+
if s_lower in _UNIT_REGISTRY:
|
|
327
|
+
return _UNIT_REGISTRY[s_lower], Scale.one
|
|
328
|
+
|
|
329
|
+
# Try scale prefix + unit (prioritize decomposition)
|
|
313
330
|
# Only case-sensitive matching for remainder (e.g., "fT" = femto-tesla, "ft" = foot)
|
|
314
331
|
for prefix in _SCALE_PREFIXES_SORTED:
|
|
315
332
|
if s.startswith(prefix) and len(s) > len(prefix):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ucon
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: A tool for dimensional analysis: a 'Unit CONverter'
|
|
5
5
|
Home-page: https://github.com/withtwoemms/ucon
|
|
6
6
|
Author: Emmanuel I. Obi
|
|
@@ -94,7 +94,7 @@ To best answer this question, we turn to an age-old technique ([dimensional anal
|
|
|
94
94
|
| **`UnitProduct`** | `ucon.core` | A product/quotient of `UnitFactor`s with exponent tracking and simplification. | Representing composite units like m/s, kg·m/s², kJ·h. |
|
|
95
95
|
| **`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. |
|
|
96
96
|
| **`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). |
|
|
97
|
-
| **`Map`** hierarchy | `ucon.maps` | Composable conversion morphisms: `LinearMap`, `AffineMap`, `ComposedMap`.
|
|
97
|
+
| **`Map`** hierarchy | `ucon.maps` | Composable conversion morphisms: `LinearMap`, `AffineMap`, `LogMap`, `ExpMap`, `ComposedMap`. | Defining conversion functions between units (e.g., meter→foot, celsius→kelvin, availability→nines). |
|
|
98
98
|
| **`ConversionGraph`** | `ucon.graph` | Registry of unit conversion edges with BFS path composition. | Converting between units via `Number.to(target)`; managing default and custom graphs. |
|
|
99
99
|
| **`UnitSystem`** | `ucon.core` | Named mapping from dimensions to base units (e.g., SI, Imperial). | Defining coherent unit systems; grouping base units by dimension. |
|
|
100
100
|
| **`BasisTransform`** | `ucon.core` | Matrix-based transformation between dimensional exponent spaces. | Converting between incompatible dimensional structures; exact arithmetic with `Fraction`. |
|
|
@@ -227,6 +227,10 @@ print(ratio.to(units.ppm)) # <500000.0 ppm>
|
|
|
227
227
|
|
|
228
228
|
# Cross-family conversions are prevented
|
|
229
229
|
units.radian(1).to(units.percent) # raises ConversionNotFound
|
|
230
|
+
|
|
231
|
+
# SRE "nines" for availability (99.999% = 5 nines)
|
|
232
|
+
uptime = units.percent(99.999)
|
|
233
|
+
print(uptime.to(units.nines)) # <5.0 nines>
|
|
230
234
|
```
|
|
231
235
|
|
|
232
236
|
### Uncertainty Propagation
|
|
@@ -278,6 +282,47 @@ m4 = Measurement(value={"quantity": 9.8, "unit": "m/s²"}) # Unicode
|
|
|
278
282
|
- **Serialization format**: Units serialize as human-readable shorthand strings (`"km"`, `"m/s^2"`) rather than structured dicts, aligning with how scientists express units.
|
|
279
283
|
- **Parsing priority**: When parsing `"kg"`, ucon returns `Scale.kilo * gram` rather than looking up a `kilogram` Unit, ensuring consistent round-trip serialization and avoiding redundant unit definitions.
|
|
280
284
|
|
|
285
|
+
### MCP Server
|
|
286
|
+
|
|
287
|
+
ucon ships with an MCP server for AI agent integration (Claude Desktop, Claude Code, Cursor, etc.):
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
pip install ucon[mcp]
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Configure in Claude Desktop (`claude_desktop_config.json`):
|
|
294
|
+
|
|
295
|
+
**Via uvx (recommended, zero-install):**
|
|
296
|
+
```json
|
|
297
|
+
{
|
|
298
|
+
"mcpServers": {
|
|
299
|
+
"ucon": {
|
|
300
|
+
"command": "uvx",
|
|
301
|
+
"args": ["--from", "ucon[mcp]", "ucon-mcp"]
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**Local development:**
|
|
308
|
+
```json
|
|
309
|
+
{
|
|
310
|
+
"mcpServers": {
|
|
311
|
+
"ucon": {
|
|
312
|
+
"command": "uv",
|
|
313
|
+
"args": ["run", "--directory", "/path/to/ucon", "--extra", "mcp", "ucon-mcp"]
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Available tools:
|
|
320
|
+
- `convert(value, from_unit, to_unit)` — Unit conversion with dimensional validation
|
|
321
|
+
- `list_units(dimension?)` — Discover available units
|
|
322
|
+
- `list_scales()` — List SI and binary prefixes
|
|
323
|
+
- `check_dimensions(unit_a, unit_b)` — Check dimensional compatibility
|
|
324
|
+
- `list_dimensions()` — List physical dimensions
|
|
325
|
+
|
|
281
326
|
### Custom Unit Systems
|
|
282
327
|
|
|
283
328
|
`BasisTransform` enables conversions between incompatible dimensional structures (e.g., fantasy game physics, CGS units, domain-specific systems).
|
|
@@ -295,7 +340,7 @@ See full example: [docs/examples/basis-transform-fantasy-units.md](./docs/exampl
|
|
|
295
340
|
| **0.5.0** | Dimensionless Units | Pseudo-dimensions for angle, solid angle, ratio | ✅ Complete |
|
|
296
341
|
| **0.5.x** | Uncertainty | Propagation through arithmetic and conversions | ✅ Complete |
|
|
297
342
|
| **0.5.x** | Unit Systems | `BasisTransform`, `UnitSystem`, cross-basis conversion | ✅ Complete |
|
|
298
|
-
| **0.6.x** | Pydantic
|
|
343
|
+
| **0.6.x** | Pydantic + MCP | API validation, AI agent integration | ✅ Complete |
|
|
299
344
|
| **0.7.x** | NumPy Arrays | Vectorized conversion and arithmetic | ⏳ Planned |
|
|
300
345
|
|
|
301
346
|
See full roadmap: [ROADMAP.md](./ROADMAP.md)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
ucon/__init__.py,sha256=SAXuDNMmxzaLVr4JpUHsz-feQotVhpzsCUj2WiXYA-0,2361
|
|
2
|
+
ucon/algebra.py,sha256=6QrPyD23L93XSrnIORcYEx2CLDv4WDcrh6H_hxeeOus,8668
|
|
3
|
+
ucon/core.py,sha256=V10GfKTf28GFgoO9NMI7ciqKHI_p8wG8qICR6u85gv0,63300
|
|
4
|
+
ucon/graph.py,sha256=vBIKwppYCAu5sw6R_3zTBlnOk2WmYMClIb6j5kDvJHI,21342
|
|
5
|
+
ucon/maps.py,sha256=-rPMOHylcQYUn62R9IU23bXdCRCRNBhdH3UD4G5IUEk,9123
|
|
6
|
+
ucon/pydantic.py,sha256=64ZR1EYFRnBGHj3VIF5pc3swdAiR2ZlYrgcntdbKN4k,5189
|
|
7
|
+
ucon/quantity.py,sha256=GBxZ_96nocx-8F-usNWGbPvWHRhRgdZzqfH9Sx69iC4,465
|
|
8
|
+
ucon/units.py,sha256=3reuG-G-BAAOiH_es8CE5jxAFTg5bkrd2JQ5C1iBTFg,16676
|
|
9
|
+
ucon/mcp/__init__.py,sha256=WoFOQ7JeDIzbjjkFIJ0Uv53VVLu-4lrjzG5vpVGGfT4,123
|
|
10
|
+
ucon/mcp/server.py,sha256=uUrdevEaR65Qjh9xn8Q-_IusNjPGxdkLF9iQmiSTs0g,7016
|
|
11
|
+
ucon-0.6.2.dist-info/licenses/LICENSE,sha256=LtimSYBSw1L_X6n1-VEdZRdwuROzPumrMUNX21asFuI,11356
|
|
12
|
+
ucon-0.6.2.dist-info/licenses/NOTICE,sha256=bh4fBOItio3kM4hSNYhqfFpcaAvOoixjD7Du8im-sYA,1079
|
|
13
|
+
ucon-0.6.2.dist-info/METADATA,sha256=5fBukT2t1v_OV17FdanlgFq6mFsKhXZuovhN6yJmg2s,17397
|
|
14
|
+
ucon-0.6.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
15
|
+
ucon-0.6.2.dist-info/entry_points.txt,sha256=jbfLf0FbOulgGa0nM_sRiTNfiCAkJcHnSSK_oj3g0cQ,50
|
|
16
|
+
ucon-0.6.2.dist-info/top_level.txt,sha256=Vv3KDuZ86fmH5yOYLbYap9DbBblK1YUkmlThffF71jA,5
|
|
17
|
+
ucon-0.6.2.dist-info/RECORD,,
|
ucon-0.6.0.dist-info/RECORD
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
ucon/__init__.py,sha256=SAXuDNMmxzaLVr4JpUHsz-feQotVhpzsCUj2WiXYA-0,2361
|
|
2
|
-
ucon/algebra.py,sha256=6QrPyD23L93XSrnIORcYEx2CLDv4WDcrh6H_hxeeOus,8668
|
|
3
|
-
ucon/core.py,sha256=V10GfKTf28GFgoO9NMI7ciqKHI_p8wG8qICR6u85gv0,63300
|
|
4
|
-
ucon/graph.py,sha256=Ec0Q2QiAGUm2RaxrKnpFHtwpNvTf4PYbvo62BWtGJG8,21159
|
|
5
|
-
ucon/maps.py,sha256=tWP4ayYCEazJzf81EP1_fmtADhg18D1eHldudAMEY0U,5460
|
|
6
|
-
ucon/pydantic.py,sha256=64ZR1EYFRnBGHj3VIF5pc3swdAiR2ZlYrgcntdbKN4k,5189
|
|
7
|
-
ucon/quantity.py,sha256=GBxZ_96nocx-8F-usNWGbPvWHRhRgdZzqfH9Sx69iC4,465
|
|
8
|
-
ucon/units.py,sha256=mcZ6LtHPjP4RYtzWTbf-tdjKtazcM1bDmxTI_tKrMxk,15924
|
|
9
|
-
ucon/mcp/__init__.py,sha256=WoFOQ7JeDIzbjjkFIJ0Uv53VVLu-4lrjzG5vpVGGfT4,123
|
|
10
|
-
ucon/mcp/server.py,sha256=uUrdevEaR65Qjh9xn8Q-_IusNjPGxdkLF9iQmiSTs0g,7016
|
|
11
|
-
ucon-0.6.0.dist-info/licenses/LICENSE,sha256=LtimSYBSw1L_X6n1-VEdZRdwuROzPumrMUNX21asFuI,11356
|
|
12
|
-
ucon-0.6.0.dist-info/licenses/NOTICE,sha256=bh4fBOItio3kM4hSNYhqfFpcaAvOoixjD7Du8im-sYA,1079
|
|
13
|
-
ucon-0.6.0.dist-info/METADATA,sha256=qdS_SH1wMJHnmWRTebu1VzWO3T935GmRMIcD9vjZ9XM,16375
|
|
14
|
-
ucon-0.6.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
15
|
-
ucon-0.6.0.dist-info/entry_points.txt,sha256=jbfLf0FbOulgGa0nM_sRiTNfiCAkJcHnSSK_oj3g0cQ,50
|
|
16
|
-
ucon-0.6.0.dist-info/top_level.txt,sha256=Vv3KDuZ86fmH5yOYLbYap9DbBblK1YUkmlThffF71jA,5
|
|
17
|
-
ucon-0.6.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|