ucon 0.3.5__py3-none-any.whl → 0.3.5rc1__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/__init__.py +1 -3
- ucon/core.py +15 -22
- ucon/quantity.py +1 -1
- {ucon-0.3.5.dist-info → ucon-0.3.5rc1.dist-info}/METADATA +32 -42
- ucon-0.3.5rc1.dist-info/RECORD +16 -0
- ucon-0.3.5.dist-info/RECORD +0 -16
- {ucon-0.3.5.dist-info → ucon-0.3.5rc1.dist-info}/WHEEL +0 -0
- {ucon-0.3.5.dist-info → ucon-0.3.5rc1.dist-info}/licenses/LICENSE +0 -0
- {ucon-0.3.5.dist-info → ucon-0.3.5rc1.dist-info}/licenses/NOTICE +0 -0
- {ucon-0.3.5.dist-info → ucon-0.3.5rc1.dist-info}/top_level.txt +0 -0
ucon/__init__.py
CHANGED
|
@@ -38,7 +38,7 @@ Design Philosophy
|
|
|
38
38
|
"""
|
|
39
39
|
from ucon import units
|
|
40
40
|
from ucon.algebra import Exponent
|
|
41
|
-
from ucon.core import Dimension, Scale, Unit
|
|
41
|
+
from ucon.core import Dimension, Scale, Unit
|
|
42
42
|
from ucon.quantity import Number, Ratio
|
|
43
43
|
|
|
44
44
|
|
|
@@ -49,7 +49,5 @@ __all__ = [
|
|
|
49
49
|
'Ratio',
|
|
50
50
|
'Scale',
|
|
51
51
|
'Unit',
|
|
52
|
-
'UnitFactor',
|
|
53
|
-
'UnitProduct',
|
|
54
52
|
'units',
|
|
55
53
|
]
|
ucon/core.py
CHANGED
|
@@ -240,7 +240,8 @@ class Scale(Enum):
|
|
|
240
240
|
|
|
241
241
|
def __mul__(self, other):
|
|
242
242
|
# --- Case 1: applying Scale to simple Unit --------------------
|
|
243
|
-
if isinstance(other, Unit):
|
|
243
|
+
if isinstance(other, Unit) and not isinstance(other, UnitProduct):
|
|
244
|
+
# Unit no longer has scale attribute - always safe to apply
|
|
244
245
|
return UnitProduct({UnitFactor(unit=other, scale=self): 1})
|
|
245
246
|
|
|
246
247
|
# --- Case 2: other cases are NOT handled here -----------------
|
|
@@ -342,6 +343,8 @@ class Unit:
|
|
|
342
343
|
Unit * Unit -> UnitProduct
|
|
343
344
|
Unit * UnitProduct -> UnitProduct
|
|
344
345
|
"""
|
|
346
|
+
from ucon.core import UnitProduct # local import to avoid circulars
|
|
347
|
+
|
|
345
348
|
if isinstance(other, UnitProduct):
|
|
346
349
|
# let UnitProduct handle merging
|
|
347
350
|
return other.__rmul__(self)
|
|
@@ -353,13 +356,12 @@ class Unit:
|
|
|
353
356
|
|
|
354
357
|
def __truediv__(self, other):
|
|
355
358
|
"""
|
|
356
|
-
Unit / Unit
|
|
359
|
+
Unit / Unit:
|
|
360
|
+
- If same unit => dimensionless Unit()
|
|
361
|
+
- If denominator is dimensionless => self
|
|
362
|
+
- Else => UnitProduct
|
|
357
363
|
"""
|
|
358
|
-
|
|
359
|
-
combined = {self: 1.0}
|
|
360
|
-
for u, exp in other.factors.items():
|
|
361
|
-
combined[u] = combined.get(u, 0.0) - exp
|
|
362
|
-
return UnitProduct(combined)
|
|
364
|
+
from ucon.core import UnitProduct # local import
|
|
363
365
|
|
|
364
366
|
if not isinstance(other, Unit):
|
|
365
367
|
return NotImplemented
|
|
@@ -383,13 +385,13 @@ class Unit:
|
|
|
383
385
|
"""
|
|
384
386
|
Unit ** n => UnitProduct with that exponent.
|
|
385
387
|
"""
|
|
388
|
+
from ucon.core import UnitProduct # local import
|
|
389
|
+
|
|
386
390
|
return UnitProduct({self: power})
|
|
387
391
|
|
|
388
392
|
# ----------------- equality & hashing -----------------
|
|
389
393
|
|
|
390
394
|
def __eq__(self, other):
|
|
391
|
-
if isinstance(other, UnitProduct):
|
|
392
|
-
return other.__eq__(self)
|
|
393
395
|
if not isinstance(other, Unit):
|
|
394
396
|
return NotImplemented
|
|
395
397
|
return (
|
|
@@ -496,7 +498,7 @@ class UnitFactor:
|
|
|
496
498
|
return NotImplemented
|
|
497
499
|
|
|
498
500
|
|
|
499
|
-
class UnitProduct:
|
|
501
|
+
class UnitProduct(Unit):
|
|
500
502
|
"""
|
|
501
503
|
Represents a product or quotient of Units.
|
|
502
504
|
|
|
@@ -525,7 +527,8 @@ class UnitProduct:
|
|
|
525
527
|
encountered UnitFactor (keeps user-intent scale).
|
|
526
528
|
"""
|
|
527
529
|
|
|
528
|
-
|
|
530
|
+
# UnitProduct always starts dimensionless
|
|
531
|
+
super().__init__(name="", dimension=Dimension.none)
|
|
529
532
|
self.aliases = ()
|
|
530
533
|
|
|
531
534
|
merged: dict[UnitFactor, float] = {}
|
|
@@ -703,16 +706,6 @@ class UnitProduct:
|
|
|
703
706
|
result *= factor.scale.value.evaluated ** power
|
|
704
707
|
return result
|
|
705
708
|
|
|
706
|
-
# ------------- Helpers ---------------------------------------------------
|
|
707
|
-
|
|
708
|
-
def _norm(self, aliases: tuple[str, ...]) -> tuple[str, ...]:
|
|
709
|
-
"""Normalize alias bag: drop empty/whitespace-only aliases."""
|
|
710
|
-
return tuple(a for a in aliases if a.strip())
|
|
711
|
-
|
|
712
|
-
def __pow__(self, power):
|
|
713
|
-
"""UnitProduct ** n => new UnitProduct with scaled exponents."""
|
|
714
|
-
return UnitProduct({u: exp * power for u, exp in self.factors.items()})
|
|
715
|
-
|
|
716
709
|
# ------------- Algebra ---------------------------------------------------
|
|
717
710
|
|
|
718
711
|
def __mul__(self, other):
|
|
@@ -806,7 +799,7 @@ class UnitProduct:
|
|
|
806
799
|
return f"<{self.__class__.__name__} {self.shorthand}>"
|
|
807
800
|
|
|
808
801
|
def __eq__(self, other):
|
|
809
|
-
if isinstance(other, Unit):
|
|
802
|
+
if isinstance(other, Unit) and not isinstance(other, UnitProduct):
|
|
810
803
|
# Only equal to a plain Unit if we have exactly that unit^1
|
|
811
804
|
# Here, the tuple comparison will invoke UnitFactor.__eq__(Unit)
|
|
812
805
|
# on the key when factors are keyed by UnitFactor.
|
ucon/quantity.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ucon
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5rc1
|
|
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
|
|
@@ -55,8 +55,8 @@ Dynamic: summary
|
|
|
55
55
|
It combines **units**, **scales**, and **dimensions** into a composable algebra that supports:
|
|
56
56
|
|
|
57
57
|
- Dimensional analysis through `Number` and `Ratio`
|
|
58
|
-
- Scale-aware arithmetic
|
|
59
|
-
- Metric and binary prefixes (`kilo`, `kibi`, `micro`, `mebi`,
|
|
58
|
+
- Scale-aware arithmetic and conversions
|
|
59
|
+
- Metric and binary prefixes (`kilo`, `kibi`, `micro`, `mebi`, ect.)
|
|
60
60
|
- A clean foundation for physics, chemistry, data modeling, and beyond
|
|
61
61
|
|
|
62
62
|
Think of it as **`decimal.Decimal` for the physical world** — precise, predictable, and type-safe.
|
|
@@ -70,22 +70,20 @@ The crux of this tiny library is to provide abstractions that simplify the answe
|
|
|
70
70
|
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:
|
|
71
71
|
| Type | Defined In | Purpose | Typical Use Cases |
|
|
72
72
|
| ----------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
73
|
-
| **`Vector`** | `ucon.
|
|
74
|
-
| **`
|
|
75
|
-
| **`
|
|
73
|
+
| **`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). |
|
|
74
|
+
| **`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). |
|
|
75
|
+
| **`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²`). |
|
|
76
76
|
| **`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). |
|
|
77
|
-
| **`
|
|
78
|
-
| **`
|
|
79
|
-
| **`
|
|
80
|
-
| **`
|
|
81
|
-
| **`Ratio`** | `ucon.quantity` | Represents the division of two `Number` objects; captures relationships between quantities. | Expressing rates, densities, efficiencies (e.g., energy / time = power, length / time = velocity). |
|
|
82
|
-
| **`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.). |
|
|
77
|
+
| **`Exponent`** | `ucon.core` | Represents base-power pairs (e.g., 10³, 2¹⁰) used by `Scale`. | Performing arithmetic on powers and bases; normalizing scales across conversions. |
|
|
78
|
+
| **`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. |
|
|
79
|
+
| **`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). |
|
|
80
|
+
| **`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.). | |
|
|
83
81
|
|
|
84
82
|
### Under the Hood
|
|
85
83
|
|
|
86
84
|
`ucon` models unit math through a hierarchy where each layer builds on the last:
|
|
87
85
|
|
|
88
|
-
<img src=https://gist.githubusercontent.com/withtwoemms/429d2ca1f979865aa80a2658bf9efa32/raw/
|
|
86
|
+
<img src=https://gist.githubusercontent.com/withtwoemms/429d2ca1f979865aa80a2658bf9efa32/raw/0c704737a52b9e4a87cda5c839e9aa40f7e5bb48/ucon.data-model_v035.png align="center" alt="ucon Data Model" width=600/>
|
|
89
87
|
|
|
90
88
|
## Why `ucon`?
|
|
91
89
|
|
|
@@ -93,22 +91,24 @@ Python already has mature libraries for handling units and physical quantities
|
|
|
93
91
|
|
|
94
92
|
| Library | Focus | Limitation |
|
|
95
93
|
| --------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
96
|
-
| **Pint** | Runtime unit conversion and compatibility checking | Treats quantities as decorated numbers — conversions work, but the algebra behind them isn
|
|
94
|
+
| **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. |
|
|
97
95
|
| **SymPy** | Symbolic algebra and simplification of unit expressions | Excellent for symbolic reasoning, but not designed for runtime validation, conversion, or serialization. |
|
|
98
96
|
| **Unum** | Unit-aware arithmetic and unit propagation | Tracks units through arithmetic but lacks explicit dimensional algebra, conversion taxonomy, or runtime introspection. |
|
|
99
97
|
|
|
100
98
|
Together, these tools can _use_ units, but none can explicitly represent and verify the relationships between units and dimensions.
|
|
101
99
|
|
|
102
|
-
That
|
|
100
|
+
That’s the gap `ucon` fills.
|
|
103
101
|
|
|
104
102
|
It treats units, dimensions, and scales as first-class objects and builds a composable algebra around them.
|
|
105
103
|
This allows you to:
|
|
106
104
|
- Represent dimensional meaning explicitly (`Dimension`, `Vector`);
|
|
107
105
|
- Compose and compute with type-safe, introspectable quantities (`Unit`, `Number`);
|
|
106
|
+
- Perform reversible, declarative conversions (standard, linear, affine, nonlinear);
|
|
107
|
+
- Serialize and validate measurements with Pydantic integration;
|
|
108
108
|
- Extend the system with custom unit registries and conversion families.
|
|
109
109
|
|
|
110
110
|
Where Pint, Unum, and SymPy focus on _how_ to compute with units,
|
|
111
|
-
`ucon` focuses on why those computations make sense. Every operation checks the dimensional structure, _not just the unit labels_. This means ucon doesn
|
|
111
|
+
`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:
|
|
112
112
|
```python
|
|
113
113
|
from ucon import Number, units
|
|
114
114
|
|
|
@@ -136,8 +136,7 @@ This sort of dimensional analysis:
|
|
|
136
136
|
```
|
|
137
137
|
becomes straightforward when you define a measurement:
|
|
138
138
|
```python
|
|
139
|
-
from ucon import Number, Scale,
|
|
140
|
-
from ucon.quantity import Ratio
|
|
139
|
+
from ucon import Number, Scale, Units, Ratio
|
|
141
140
|
|
|
142
141
|
# Two milliliters of bromine
|
|
143
142
|
mL = Scale.milli * units.liter
|
|
@@ -150,36 +149,27 @@ bromine_density = Ratio(
|
|
|
150
149
|
)
|
|
151
150
|
|
|
152
151
|
# Multiply to find mass
|
|
153
|
-
grams_bromine =
|
|
154
|
-
print(grams_bromine) # <6.238
|
|
152
|
+
grams_bromine = two_mL_bromine * bromine_density
|
|
153
|
+
print(grams_bromine) # <6.238 gram>
|
|
155
154
|
```
|
|
156
155
|
|
|
157
|
-
Scale
|
|
158
|
-
```python
|
|
159
|
-
km = Scale.kilo * units.meter # UnitProduct with kilo-scaled meter
|
|
160
|
-
mg = Scale.milli * units.gram # UnitProduct with milli-scaled gram
|
|
161
|
-
|
|
162
|
-
print(km.shorthand) # 'km'
|
|
163
|
-
print(mg.shorthand) # 'mg'
|
|
156
|
+
Scale conversion is automatic and precise:
|
|
164
157
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
158
|
+
```python
|
|
159
|
+
grams_bromine.to(Scale.milli) # <6238.0 milligram>
|
|
160
|
+
grams_bromine.to(Scale.kibi) # <0.006091796875 kibigram>
|
|
168
161
|
```
|
|
169
162
|
|
|
170
|
-
> **Note:** Unit _conversions_ (e.g., `number.to(units.inch)`) are planned for v0.4.x
|
|
171
|
-
> via the `ConversionGraph` abstraction. See [ROADMAP.md](./ROADMAP.md).
|
|
172
|
-
|
|
173
163
|
---
|
|
174
164
|
|
|
175
165
|
## Roadmap Highlights
|
|
176
166
|
|
|
177
|
-
| Version | Theme | Focus |
|
|
178
|
-
|
|
179
|
-
| **0.3.
|
|
180
|
-
| [**0.4.x**](https://github.com/withtwoemms/ucon/milestone/2) | Conversion System |
|
|
181
|
-
| [**0.6.x**](https://github.com/withtwoemms/ucon/milestone/4) | Nonlinear / Specialized Units | Decibel, Percent, pH |
|
|
182
|
-
| [**0.8.x**](https://github.com/withtwoemms/ucon/milestone/6) | Pydantic Integration | Type-safe quantity validation |
|
|
167
|
+
| Version | Theme | Focus |
|
|
168
|
+
|----------|-------|--------|
|
|
169
|
+
| [**0.3.x**](https://github.com/withtwoemms/ucon/milestone/1) | Primitive Type Refinement | Unified algebraic foundation |
|
|
170
|
+
| [**0.4.x**](https://github.com/withtwoemms/ucon/milestone/2) | Conversion System | Linear & affine conversions |
|
|
171
|
+
| [**0.6.x**](https://github.com/withtwoemms/ucon/milestone/4) | Nonlinear / Specialized Units | Decibel, Percent, pH |
|
|
172
|
+
| [**0.8.x**](https://github.com/withtwoemms/ucon/milestone/6) | Pydantic Integration | Type-safe quantity validation |
|
|
183
173
|
|
|
184
174
|
See full roadmap: [ROADMAP.md](./ROADMAP.md)
|
|
185
175
|
|
|
@@ -192,13 +182,13 @@ Ensure `nox` is installed.
|
|
|
192
182
|
```
|
|
193
183
|
pip install -r requirements.txt
|
|
194
184
|
```
|
|
195
|
-
Then run the full test suite (
|
|
185
|
+
Then run the full test suite (agains all supported python versions) before committing:
|
|
196
186
|
|
|
197
187
|
```bash
|
|
198
188
|
nox -s test
|
|
199
189
|
```
|
|
200
190
|
---
|
|
201
191
|
|
|
202
|
-
>
|
|
192
|
+
> “If it can be measured, it can be represented.
|
|
203
193
|
If it can be represented, it can be validated.
|
|
204
|
-
If it can be validated, it can be trusted
|
|
194
|
+
If it can be validated, it can be trusted.”
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
tests/ucon/__init__.py,sha256=9BAHYTs27Ed3VgqiMUH4XtVttAmOPgK0Zvj-dUNo7D8,119
|
|
2
|
+
tests/ucon/test_algebra.py,sha256=0mxkiXibZfnzYtbscgVXPDcX1JelrVpcqNBcQe3cn3g,8330
|
|
3
|
+
tests/ucon/test_core.py,sha256=x5JLJAKuaTBkxQzYqTFnDaStVcIlnCviJNiN2OJ7KGQ,32435
|
|
4
|
+
tests/ucon/test_quantity.py,sha256=YLV78_t4AkZcJeEGu-lBvIXNLhTV_MLkTbIKV67rs4Y,14955
|
|
5
|
+
tests/ucon/test_units.py,sha256=SILymDtDNDyxEhkYQubrfkakKCMexwEwjyHfhrkDrMI,869
|
|
6
|
+
ucon/__init__.py,sha256=vJ6A2BU6s2_3vW4fExhn3VEjbn8yrvgF2hYBfGrKPrY,1865
|
|
7
|
+
ucon/algebra.py,sha256=ZVF8B2kUOeSN20R-lTHJNJDxe_Zv7s8kJ70F2JOSYxk,7262
|
|
8
|
+
ucon/core.py,sha256=cjq0hc5L7iA3ObWUT9JetUnWN6-WWqoQJ7c9YWbS35Y,29597
|
|
9
|
+
ucon/quantity.py,sha256=rjJLx1bktnfddfgn80m3eyVEPq0LU9RmUVR0aOeopqM,7290
|
|
10
|
+
ucon/units.py,sha256=-CShNMLr9t7f3pyYsfmZv3wMCZU4lEnoe8r_9YQWjxA,3783
|
|
11
|
+
ucon-0.3.5rc1.dist-info/licenses/LICENSE,sha256=LtimSYBSw1L_X6n1-VEdZRdwuROzPumrMUNX21asFuI,11356
|
|
12
|
+
ucon-0.3.5rc1.dist-info/licenses/NOTICE,sha256=bh4fBOItio3kM4hSNYhqfFpcaAvOoixjD7Du8im-sYA,1079
|
|
13
|
+
ucon-0.3.5rc1.dist-info/METADATA,sha256=EqRVt-FxtnB-C73U_-JZqzouAKJl_y3ofiBAKxxBVtM,10626
|
|
14
|
+
ucon-0.3.5rc1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
15
|
+
ucon-0.3.5rc1.dist-info/top_level.txt,sha256=zZYRJiQrVUtN32ziJD2YEq7ClSvDmVYHYy5ArRAZGxI,11
|
|
16
|
+
ucon-0.3.5rc1.dist-info/RECORD,,
|
ucon-0.3.5.dist-info/RECORD
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
tests/ucon/__init__.py,sha256=9BAHYTs27Ed3VgqiMUH4XtVttAmOPgK0Zvj-dUNo7D8,119
|
|
2
|
-
tests/ucon/test_algebra.py,sha256=0mxkiXibZfnzYtbscgVXPDcX1JelrVpcqNBcQe3cn3g,8330
|
|
3
|
-
tests/ucon/test_core.py,sha256=x5JLJAKuaTBkxQzYqTFnDaStVcIlnCviJNiN2OJ7KGQ,32435
|
|
4
|
-
tests/ucon/test_quantity.py,sha256=YLV78_t4AkZcJeEGu-lBvIXNLhTV_MLkTbIKV67rs4Y,14955
|
|
5
|
-
tests/ucon/test_units.py,sha256=SILymDtDNDyxEhkYQubrfkakKCMexwEwjyHfhrkDrMI,869
|
|
6
|
-
ucon/__init__.py,sha256=Va7KJ5ImQCkf06TWPKs0r6kfziURsvGh5I63ipiYiLo,1927
|
|
7
|
-
ucon/algebra.py,sha256=ZVF8B2kUOeSN20R-lTHJNJDxe_Zv7s8kJ70F2JOSYxk,7262
|
|
8
|
-
ucon/core.py,sha256=Dx8HNwjGpF-RFlO_2Cz1BZikRFeLcYlMy7hscw106vo,29825
|
|
9
|
-
ucon/quantity.py,sha256=skXge9RU-5dW1ULCV6kiE4jk-rMVzXpBa4hV4mVr_Eo,7310
|
|
10
|
-
ucon/units.py,sha256=-CShNMLr9t7f3pyYsfmZv3wMCZU4lEnoe8r_9YQWjxA,3783
|
|
11
|
-
ucon-0.3.5.dist-info/licenses/LICENSE,sha256=LtimSYBSw1L_X6n1-VEdZRdwuROzPumrMUNX21asFuI,11356
|
|
12
|
-
ucon-0.3.5.dist-info/licenses/NOTICE,sha256=bh4fBOItio3kM4hSNYhqfFpcaAvOoixjD7Du8im-sYA,1079
|
|
13
|
-
ucon-0.3.5.dist-info/METADATA,sha256=unyLeaX8cl9Uf-EaX1NnylgaW5yUBLf_k22-cfCzaq0,11429
|
|
14
|
-
ucon-0.3.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
15
|
-
ucon-0.3.5.dist-info/top_level.txt,sha256=zZYRJiQrVUtN32ziJD2YEq7ClSvDmVYHYy5ArRAZGxI,11
|
|
16
|
-
ucon-0.3.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|