python-units 0.1.2.post1__tar.gz → 0.3.0__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.
- python_units-0.3.0/LICENSE +0 -0
- python_units-0.3.0/PKG-INFO +289 -0
- python_units-0.3.0/README.md +263 -0
- python_units-0.3.0/pyproject.toml +41 -0
- python_units-0.3.0/setup.py +7 -0
- python_units-0.3.0/src/adapters/__init__.py +1 -0
- python_units-0.3.0/src/api/__init__.py +3 -0
- python_units-0.3.0/src/api/public.py +110 -0
- python_units-0.3.0/src/api/si.py +88 -0
- python_units-0.3.0/src/core/__init__.py +42 -0
- python_units-0.3.0/src/core/deprecations.py +62 -0
- python_units-0.3.0/src/core/errors.py +22 -0
- python_units-0.3.0/src/core/quantity.py +255 -0
- python_units-0.3.0/src/core/unit_definitions.py +307 -0
- python_units-0.3.0/src/models/__init__.py +5 -0
- python_units-0.3.0/src/models/dimension.py +106 -0
- python_units-0.3.0/src/python_units.egg-info/PKG-INFO +289 -0
- python_units-0.3.0/src/python_units.egg-info/SOURCES.txt +29 -0
- python_units-0.3.0/src/python_units.egg-info/requires.txt +7 -0
- python_units-0.3.0/src/python_units.egg-info/top_level.txt +7 -0
- python_units-0.3.0/src/services/__init__.py +1 -0
- python_units-0.3.0/src/units/__init__.py +13 -0
- python_units-0.3.0/src/units/dimension.py +6 -0
- python_units-0.3.0/src/units/errors.py +18 -0
- python_units-0.3.0/src/units/quantity.py +28 -0
- python_units-0.3.0/src/units/si.py +4 -0
- python_units-0.3.0/src/units/unit.py +24 -0
- python_units-0.3.0/src/utils/__init__.py +5 -0
- python_units-0.3.0/src/utils/numbers.py +29 -0
- python-units-0.1.2.post1/PKG-INFO +0 -251
- python-units-0.1.2.post1/README.rst +0 -240
- python-units-0.1.2.post1/python_units.egg-info/PKG-INFO +0 -251
- python-units-0.1.2.post1/python_units.egg-info/SOURCES.txt +0 -8
- python-units-0.1.2.post1/python_units.egg-info/top_level.txt +0 -1
- python-units-0.1.2.post1/setup.py +0 -28
- python-units-0.1.2.post1/units/__init__.py +0 -534
- python-units-0.1.2.post1/units/tests.py +0 -153
- {python-units-0.1.2.post1 → python_units-0.3.0}/setup.cfg +0 -0
- {python-units-0.1.2.post1 → python_units-0.3.0/src}/python_units.egg-info/dependency_links.txt +0 -0
|
File without changes
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-units
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Python library to represent numbers with units
|
|
5
|
+
Author-email: "Paul K. Korir, PhD" <paul.korir@gmail.com>
|
|
6
|
+
License-Expression: GPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://github.com/sci2pro/python-units
|
|
8
|
+
Keywords: units
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: build; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
23
|
+
Requires-Dist: tox; extra == "dev"
|
|
24
|
+
Requires-Dist: twine; extra == "dev"
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# units
|
|
28
|
+
|
|
29
|
+
[](https://badge.fury.io/py/python-units)
|
|
30
|
+
[](https://pypi.org/project/python-units/)
|
|
31
|
+
[](/Users/paulkorir/PycharmProjects/python-units/tests/unit/test_units.py)
|
|
32
|
+
|
|
33
|
+
Python library to represent quantities with units.
|
|
34
|
+
|
|
35
|
+
Supported Python versions: 3.10+
|
|
36
|
+
|
|
37
|
+
Python 2 is not supported.
|
|
38
|
+
|
|
39
|
+
Project layout:
|
|
40
|
+
|
|
41
|
+
- public facade: `src/units`
|
|
42
|
+
- API exports: `src/api`
|
|
43
|
+
- business logic: `src/core`
|
|
44
|
+
- data models: `src/models`
|
|
45
|
+
- utilities: `src/utils`
|
|
46
|
+
- tests: `tests/unit` and `tests/integration`
|
|
47
|
+
|
|
48
|
+
Preferred API:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from units import Quantity
|
|
52
|
+
from units.si import metre, second, newton
|
|
53
|
+
|
|
54
|
+
distance = 10 * metre
|
|
55
|
+
time = 2 * second
|
|
56
|
+
speed = distance / time
|
|
57
|
+
force = 5 * newton
|
|
58
|
+
print(distance)
|
|
59
|
+
print(speed)
|
|
60
|
+
print(force)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The preferred construction style is scalar-by-unit multiplication:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from units.si import metre, second
|
|
67
|
+
|
|
68
|
+
length = 3 * metre
|
|
69
|
+
time = 2 * second
|
|
70
|
+
speed = length / time
|
|
71
|
+
volume = 5 * metre ** 3
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Because `**` binds more tightly than `*`, `5 * metre ** 3` is interpreted as
|
|
75
|
+
`5 * (metre ** 3)`, which is the intended geometric-unit behavior.
|
|
76
|
+
|
|
77
|
+
The explicit constructor remains supported and is still the right low-level form
|
|
78
|
+
when you want to be fully explicit:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from units import Quantity
|
|
82
|
+
from units.si import metre
|
|
83
|
+
|
|
84
|
+
length = Quantity(3, metre)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Legacy API compatibility:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
import units as u
|
|
91
|
+
print(u.Unit(1, u.metre))
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The legacy `Unit` constructor remains available as a compatibility alias for
|
|
95
|
+
`Quantity` during the migration period. It is deprecated and scheduled for
|
|
96
|
+
removal in `1.0.0`, but it remains a true alias until then so existing type
|
|
97
|
+
checks keep working. New code should prefer `from units import Quantity` and
|
|
98
|
+
`from units.si import ...`.
|
|
99
|
+
|
|
100
|
+
The package is Python 3-only. Python 2 compatibility behavior is not part of the
|
|
101
|
+
supported interface.
|
|
102
|
+
|
|
103
|
+
# Migration guide
|
|
104
|
+
|
|
105
|
+
Old style:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
import units as u
|
|
109
|
+
distance = u.Unit(3, u.metre)
|
|
110
|
+
time = u.Unit(2, u.second)
|
|
111
|
+
speed = distance / time
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
New style:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from units.si import metre, second
|
|
118
|
+
|
|
119
|
+
distance = 3 * metre
|
|
120
|
+
time = 2 * second
|
|
121
|
+
speed = distance / time
|
|
122
|
+
volume = 5 * metre ** 3
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Still supported when you want the fully explicit constructor form:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from units import Quantity
|
|
129
|
+
from units.si import metre, second
|
|
130
|
+
|
|
131
|
+
distance = Quantity(3, metre)
|
|
132
|
+
time = Quantity(2, second)
|
|
133
|
+
speed = distance / time
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
# Public API
|
|
137
|
+
|
|
138
|
+
Stable top-level imports:
|
|
139
|
+
|
|
140
|
+
* `Quantity`
|
|
141
|
+
* `Unit` (compatibility alias for `Quantity`)
|
|
142
|
+
* `UnitsError`, `InvalidUnitError`, `InvalidValueError`,
|
|
143
|
+
`UnitCompatibilityError`, `UnitOperandError`
|
|
144
|
+
|
|
145
|
+
Canonical unit imports:
|
|
146
|
+
|
|
147
|
+
* `from units.si import metre, second, newton`
|
|
148
|
+
|
|
149
|
+
Legacy compatibility helpers:
|
|
150
|
+
|
|
151
|
+
* `Unit`
|
|
152
|
+
* `long_quantity`
|
|
153
|
+
* `int_unit`
|
|
154
|
+
* `float_unit`
|
|
155
|
+
* `long_unit`
|
|
156
|
+
* `complex_unit`
|
|
157
|
+
|
|
158
|
+
These names remain available during the migration period and emit
|
|
159
|
+
`DeprecationWarning` when called. `Unit` remains a true alias for `Quantity` and
|
|
160
|
+
does not emit a call-time warning, because preserving `Unit is Quantity` is part
|
|
161
|
+
of the pre-`1.0.0` compatibility contract. New code should prefer `Quantity`,
|
|
162
|
+
scalar-by-unit construction, and the `*_quantity` conversion helpers. The
|
|
163
|
+
deprecated compatibility paths are scheduled for removal in `1.0.0`.
|
|
164
|
+
|
|
165
|
+
# Notes on semantics
|
|
166
|
+
|
|
167
|
+
* Addition and subtraction require identical units.
|
|
168
|
+
* Multiplication and division combine units algebraically.
|
|
169
|
+
* Integer powers of units and unit-bearing quantities are supported.
|
|
170
|
+
* Unitless quantities are supported explicitly.
|
|
171
|
+
* The core quantity model allows signed values. Domain-specific constraints such
|
|
172
|
+
as non-negative lengths should be enforced by higher-level types or validators.
|
|
173
|
+
|
|
174
|
+
# Real-world examples
|
|
175
|
+
|
|
176
|
+
## Electrical engineering: from resistance to power dissipation
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from units.si import ampere, ohm, volt, watt
|
|
180
|
+
|
|
181
|
+
current = 12 * ampere
|
|
182
|
+
resistance = 8 * ohm
|
|
183
|
+
voltage = current * resistance
|
|
184
|
+
power = voltage * current
|
|
185
|
+
|
|
186
|
+
print(voltage) # 96 V
|
|
187
|
+
print(power) # 1152 W
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
This works because the package canonicalizes unambiguous derived-unit assemblies:
|
|
191
|
+
|
|
192
|
+
- `ampere * ohm -> volt`
|
|
193
|
+
- `volt * ampere -> watt`
|
|
194
|
+
|
|
195
|
+
## Pump sizing: hydraulic power from pressure rise and flow rate
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
from units.si import metre, second, kilogram, pascal, watt
|
|
199
|
+
|
|
200
|
+
density = 998 * (kilogram / metre ** 3)
|
|
201
|
+
flow_velocity = 2.5 * (metre / second)
|
|
202
|
+
pipe_area = 0.0314 * metre ** 2
|
|
203
|
+
pressure_rise = 180000 * pascal
|
|
204
|
+
|
|
205
|
+
volumetric_flow = flow_velocity * pipe_area
|
|
206
|
+
hydraulic_power = pressure_rise * volumetric_flow
|
|
207
|
+
|
|
208
|
+
print(volumetric_flow) # m^3·s^-1
|
|
209
|
+
print(hydraulic_power) # W
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
This is a good example of a multi-step engineering computation that still renders
|
|
213
|
+
to intuitive derived units at the end of the chain.
|
|
214
|
+
|
|
215
|
+
## Structural mechanics: work from force over distance
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
from units.si import metre, newton
|
|
219
|
+
|
|
220
|
+
force = 4200 * newton
|
|
221
|
+
displacement = 0.35 * metre
|
|
222
|
+
work = force * displacement
|
|
223
|
+
|
|
224
|
+
print(work) # J
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Geometric quantities: powers of units
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
from units.si import metre
|
|
231
|
+
|
|
232
|
+
volume = 5 * metre ** 3
|
|
233
|
+
area = (12 * metre) ** 2
|
|
234
|
+
|
|
235
|
+
print(volume) # 5 m^3
|
|
236
|
+
print(area) # 144 m^2
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The unit form is also valid on its own:
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
from units.si import metre
|
|
243
|
+
|
|
244
|
+
area_unit = metre ** 2
|
|
245
|
+
volume_unit = metre ** 3
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Fluid mechanics: dynamic pressure
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
from units.si import kilogram, metre, pascal, second
|
|
252
|
+
|
|
253
|
+
density = 1.225 * (kilogram / metre ** 3)
|
|
254
|
+
velocity = 68 * (metre / second)
|
|
255
|
+
dynamic_pressure = 0.5 * density * velocity * velocity
|
|
256
|
+
|
|
257
|
+
print(dynamic_pressure) # Pa
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Custom unit systems
|
|
261
|
+
|
|
262
|
+
Custom unit systems are supported, but they are intentionally separate from SI
|
|
263
|
+
canonicalization. Use them when you want the same algebra and formatting
|
|
264
|
+
behaviour without forcing your units into the SI registry.
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
from units import CustomUnitBase, DimensionSystem
|
|
268
|
+
|
|
269
|
+
class CommUnit(CustomUnitBase):
|
|
270
|
+
dimension_system = DimensionSystem('comm', ('b', 's', 'B'))
|
|
271
|
+
|
|
272
|
+
bit = CommUnit.define('b')
|
|
273
|
+
second = CommUnit.define('s')
|
|
274
|
+
|
|
275
|
+
data = 32 * bit
|
|
276
|
+
duration = 4 * second
|
|
277
|
+
rate = data / duration
|
|
278
|
+
|
|
279
|
+
print(rate) # 8.0 b·s^-1
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Custom systems inherit useful behaviour:
|
|
283
|
+
|
|
284
|
+
- dimensional algebra
|
|
285
|
+
- string rendering
|
|
286
|
+
- incompatibility checks within a system
|
|
287
|
+
|
|
288
|
+
They do not automatically simplify into SI-derived names such as `V`, `J`, or
|
|
289
|
+
`Pa`, and they cannot be mixed with SI units unless you build an explicit bridge.
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# units
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/py/python-units)
|
|
4
|
+
[](https://pypi.org/project/python-units/)
|
|
5
|
+
[](/Users/paulkorir/PycharmProjects/python-units/tests/unit/test_units.py)
|
|
6
|
+
|
|
7
|
+
Python library to represent quantities with units.
|
|
8
|
+
|
|
9
|
+
Supported Python versions: 3.10+
|
|
10
|
+
|
|
11
|
+
Python 2 is not supported.
|
|
12
|
+
|
|
13
|
+
Project layout:
|
|
14
|
+
|
|
15
|
+
- public facade: `src/units`
|
|
16
|
+
- API exports: `src/api`
|
|
17
|
+
- business logic: `src/core`
|
|
18
|
+
- data models: `src/models`
|
|
19
|
+
- utilities: `src/utils`
|
|
20
|
+
- tests: `tests/unit` and `tests/integration`
|
|
21
|
+
|
|
22
|
+
Preferred API:
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from units import Quantity
|
|
26
|
+
from units.si import metre, second, newton
|
|
27
|
+
|
|
28
|
+
distance = 10 * metre
|
|
29
|
+
time = 2 * second
|
|
30
|
+
speed = distance / time
|
|
31
|
+
force = 5 * newton
|
|
32
|
+
print(distance)
|
|
33
|
+
print(speed)
|
|
34
|
+
print(force)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The preferred construction style is scalar-by-unit multiplication:
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from units.si import metre, second
|
|
41
|
+
|
|
42
|
+
length = 3 * metre
|
|
43
|
+
time = 2 * second
|
|
44
|
+
speed = length / time
|
|
45
|
+
volume = 5 * metre ** 3
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Because `**` binds more tightly than `*`, `5 * metre ** 3` is interpreted as
|
|
49
|
+
`5 * (metre ** 3)`, which is the intended geometric-unit behavior.
|
|
50
|
+
|
|
51
|
+
The explicit constructor remains supported and is still the right low-level form
|
|
52
|
+
when you want to be fully explicit:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from units import Quantity
|
|
56
|
+
from units.si import metre
|
|
57
|
+
|
|
58
|
+
length = Quantity(3, metre)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Legacy API compatibility:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import units as u
|
|
65
|
+
print(u.Unit(1, u.metre))
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The legacy `Unit` constructor remains available as a compatibility alias for
|
|
69
|
+
`Quantity` during the migration period. It is deprecated and scheduled for
|
|
70
|
+
removal in `1.0.0`, but it remains a true alias until then so existing type
|
|
71
|
+
checks keep working. New code should prefer `from units import Quantity` and
|
|
72
|
+
`from units.si import ...`.
|
|
73
|
+
|
|
74
|
+
The package is Python 3-only. Python 2 compatibility behavior is not part of the
|
|
75
|
+
supported interface.
|
|
76
|
+
|
|
77
|
+
# Migration guide
|
|
78
|
+
|
|
79
|
+
Old style:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
import units as u
|
|
83
|
+
distance = u.Unit(3, u.metre)
|
|
84
|
+
time = u.Unit(2, u.second)
|
|
85
|
+
speed = distance / time
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
New style:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from units.si import metre, second
|
|
92
|
+
|
|
93
|
+
distance = 3 * metre
|
|
94
|
+
time = 2 * second
|
|
95
|
+
speed = distance / time
|
|
96
|
+
volume = 5 * metre ** 3
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Still supported when you want the fully explicit constructor form:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from units import Quantity
|
|
103
|
+
from units.si import metre, second
|
|
104
|
+
|
|
105
|
+
distance = Quantity(3, metre)
|
|
106
|
+
time = Quantity(2, second)
|
|
107
|
+
speed = distance / time
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
# Public API
|
|
111
|
+
|
|
112
|
+
Stable top-level imports:
|
|
113
|
+
|
|
114
|
+
* `Quantity`
|
|
115
|
+
* `Unit` (compatibility alias for `Quantity`)
|
|
116
|
+
* `UnitsError`, `InvalidUnitError`, `InvalidValueError`,
|
|
117
|
+
`UnitCompatibilityError`, `UnitOperandError`
|
|
118
|
+
|
|
119
|
+
Canonical unit imports:
|
|
120
|
+
|
|
121
|
+
* `from units.si import metre, second, newton`
|
|
122
|
+
|
|
123
|
+
Legacy compatibility helpers:
|
|
124
|
+
|
|
125
|
+
* `Unit`
|
|
126
|
+
* `long_quantity`
|
|
127
|
+
* `int_unit`
|
|
128
|
+
* `float_unit`
|
|
129
|
+
* `long_unit`
|
|
130
|
+
* `complex_unit`
|
|
131
|
+
|
|
132
|
+
These names remain available during the migration period and emit
|
|
133
|
+
`DeprecationWarning` when called. `Unit` remains a true alias for `Quantity` and
|
|
134
|
+
does not emit a call-time warning, because preserving `Unit is Quantity` is part
|
|
135
|
+
of the pre-`1.0.0` compatibility contract. New code should prefer `Quantity`,
|
|
136
|
+
scalar-by-unit construction, and the `*_quantity` conversion helpers. The
|
|
137
|
+
deprecated compatibility paths are scheduled for removal in `1.0.0`.
|
|
138
|
+
|
|
139
|
+
# Notes on semantics
|
|
140
|
+
|
|
141
|
+
* Addition and subtraction require identical units.
|
|
142
|
+
* Multiplication and division combine units algebraically.
|
|
143
|
+
* Integer powers of units and unit-bearing quantities are supported.
|
|
144
|
+
* Unitless quantities are supported explicitly.
|
|
145
|
+
* The core quantity model allows signed values. Domain-specific constraints such
|
|
146
|
+
as non-negative lengths should be enforced by higher-level types or validators.
|
|
147
|
+
|
|
148
|
+
# Real-world examples
|
|
149
|
+
|
|
150
|
+
## Electrical engineering: from resistance to power dissipation
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from units.si import ampere, ohm, volt, watt
|
|
154
|
+
|
|
155
|
+
current = 12 * ampere
|
|
156
|
+
resistance = 8 * ohm
|
|
157
|
+
voltage = current * resistance
|
|
158
|
+
power = voltage * current
|
|
159
|
+
|
|
160
|
+
print(voltage) # 96 V
|
|
161
|
+
print(power) # 1152 W
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
This works because the package canonicalizes unambiguous derived-unit assemblies:
|
|
165
|
+
|
|
166
|
+
- `ampere * ohm -> volt`
|
|
167
|
+
- `volt * ampere -> watt`
|
|
168
|
+
|
|
169
|
+
## Pump sizing: hydraulic power from pressure rise and flow rate
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from units.si import metre, second, kilogram, pascal, watt
|
|
173
|
+
|
|
174
|
+
density = 998 * (kilogram / metre ** 3)
|
|
175
|
+
flow_velocity = 2.5 * (metre / second)
|
|
176
|
+
pipe_area = 0.0314 * metre ** 2
|
|
177
|
+
pressure_rise = 180000 * pascal
|
|
178
|
+
|
|
179
|
+
volumetric_flow = flow_velocity * pipe_area
|
|
180
|
+
hydraulic_power = pressure_rise * volumetric_flow
|
|
181
|
+
|
|
182
|
+
print(volumetric_flow) # m^3·s^-1
|
|
183
|
+
print(hydraulic_power) # W
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
This is a good example of a multi-step engineering computation that still renders
|
|
187
|
+
to intuitive derived units at the end of the chain.
|
|
188
|
+
|
|
189
|
+
## Structural mechanics: work from force over distance
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
from units.si import metre, newton
|
|
193
|
+
|
|
194
|
+
force = 4200 * newton
|
|
195
|
+
displacement = 0.35 * metre
|
|
196
|
+
work = force * displacement
|
|
197
|
+
|
|
198
|
+
print(work) # J
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Geometric quantities: powers of units
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from units.si import metre
|
|
205
|
+
|
|
206
|
+
volume = 5 * metre ** 3
|
|
207
|
+
area = (12 * metre) ** 2
|
|
208
|
+
|
|
209
|
+
print(volume) # 5 m^3
|
|
210
|
+
print(area) # 144 m^2
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The unit form is also valid on its own:
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
from units.si import metre
|
|
217
|
+
|
|
218
|
+
area_unit = metre ** 2
|
|
219
|
+
volume_unit = metre ** 3
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Fluid mechanics: dynamic pressure
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
from units.si import kilogram, metre, pascal, second
|
|
226
|
+
|
|
227
|
+
density = 1.225 * (kilogram / metre ** 3)
|
|
228
|
+
velocity = 68 * (metre / second)
|
|
229
|
+
dynamic_pressure = 0.5 * density * velocity * velocity
|
|
230
|
+
|
|
231
|
+
print(dynamic_pressure) # Pa
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Custom unit systems
|
|
235
|
+
|
|
236
|
+
Custom unit systems are supported, but they are intentionally separate from SI
|
|
237
|
+
canonicalization. Use them when you want the same algebra and formatting
|
|
238
|
+
behaviour without forcing your units into the SI registry.
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
from units import CustomUnitBase, DimensionSystem
|
|
242
|
+
|
|
243
|
+
class CommUnit(CustomUnitBase):
|
|
244
|
+
dimension_system = DimensionSystem('comm', ('b', 's', 'B'))
|
|
245
|
+
|
|
246
|
+
bit = CommUnit.define('b')
|
|
247
|
+
second = CommUnit.define('s')
|
|
248
|
+
|
|
249
|
+
data = 32 * bit
|
|
250
|
+
duration = 4 * second
|
|
251
|
+
rate = data / duration
|
|
252
|
+
|
|
253
|
+
print(rate) # 8.0 b·s^-1
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Custom systems inherit useful behaviour:
|
|
257
|
+
|
|
258
|
+
- dimensional algebra
|
|
259
|
+
- string rendering
|
|
260
|
+
- incompatibility checks within a system
|
|
261
|
+
|
|
262
|
+
They do not automatically simplify into SI-derived names such as `V`, `J`, or
|
|
263
|
+
`Pa`, and they cannot be mixed with SI units unless you build an explicit bridge.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "python-units"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "Python library to represent numbers with units"
|
|
9
|
+
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "GPL-3.0-or-later"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Paul K. Korir, PhD", email = "paul.korir@gmail.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["units"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Programming Language :: Python :: 3.14",
|
|
24
|
+
]
|
|
25
|
+
dependencies = []
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
dev = [
|
|
29
|
+
"build",
|
|
30
|
+
"pytest",
|
|
31
|
+
"pytest-cov",
|
|
32
|
+
"tox",
|
|
33
|
+
"twine",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/sci2pro/python-units"
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.packages.find]
|
|
40
|
+
where = ["src"]
|
|
41
|
+
include = ["adapters*", "api*", "core*", "models*", "services*", "units*", "utils*"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Adapter-layer package reserved for external integrations."""
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Public export surface for the units package."""
|
|
3
|
+
|
|
4
|
+
from api.si import (
|
|
5
|
+
ampere,
|
|
6
|
+
becquerel,
|
|
7
|
+
candela,
|
|
8
|
+
coulomb,
|
|
9
|
+
degree_celcius,
|
|
10
|
+
farad,
|
|
11
|
+
gray,
|
|
12
|
+
henry,
|
|
13
|
+
hertz,
|
|
14
|
+
joule,
|
|
15
|
+
katal,
|
|
16
|
+
kelvin,
|
|
17
|
+
kilogram,
|
|
18
|
+
lumen,
|
|
19
|
+
lux,
|
|
20
|
+
metre,
|
|
21
|
+
mole,
|
|
22
|
+
newton,
|
|
23
|
+
ohm,
|
|
24
|
+
pascal,
|
|
25
|
+
radian,
|
|
26
|
+
second,
|
|
27
|
+
siemens,
|
|
28
|
+
sievert,
|
|
29
|
+
steradian,
|
|
30
|
+
tesla,
|
|
31
|
+
volt,
|
|
32
|
+
watt,
|
|
33
|
+
weber,
|
|
34
|
+
)
|
|
35
|
+
from core.errors import (
|
|
36
|
+
InvalidUnitError,
|
|
37
|
+
InvalidValueError,
|
|
38
|
+
UnitCompatibilityError,
|
|
39
|
+
UnitOperandError,
|
|
40
|
+
UnitsError,
|
|
41
|
+
)
|
|
42
|
+
from core.quantity import (
|
|
43
|
+
Quantity,
|
|
44
|
+
complex_quantity,
|
|
45
|
+
complex_unit,
|
|
46
|
+
float_quantity,
|
|
47
|
+
float_unit,
|
|
48
|
+
int_quantity,
|
|
49
|
+
int_unit,
|
|
50
|
+
long_quantity,
|
|
51
|
+
long_unit,
|
|
52
|
+
)
|
|
53
|
+
from core.unit_definitions import BaseUnit, CustomUnitBase, DerivedUnit, SIUnit
|
|
54
|
+
from models.dimension import Dimension, DimensionSystem
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
Unit = Quantity
|
|
58
|
+
|
|
59
|
+
__all__ = [
|
|
60
|
+
"Dimension",
|
|
61
|
+
"DimensionSystem",
|
|
62
|
+
"Quantity",
|
|
63
|
+
"Unit",
|
|
64
|
+
"UnitsError",
|
|
65
|
+
"InvalidUnitError",
|
|
66
|
+
"InvalidValueError",
|
|
67
|
+
"UnitCompatibilityError",
|
|
68
|
+
"UnitOperandError",
|
|
69
|
+
"BaseUnit",
|
|
70
|
+
"CustomUnitBase",
|
|
71
|
+
"DerivedUnit",
|
|
72
|
+
"SIUnit",
|
|
73
|
+
"ampere",
|
|
74
|
+
"becquerel",
|
|
75
|
+
"candela",
|
|
76
|
+
"complex_quantity",
|
|
77
|
+
"complex_unit",
|
|
78
|
+
"coulomb",
|
|
79
|
+
"degree_celcius",
|
|
80
|
+
"farad",
|
|
81
|
+
"float_quantity",
|
|
82
|
+
"float_unit",
|
|
83
|
+
"gray",
|
|
84
|
+
"henry",
|
|
85
|
+
"hertz",
|
|
86
|
+
"int_quantity",
|
|
87
|
+
"int_unit",
|
|
88
|
+
"joule",
|
|
89
|
+
"katal",
|
|
90
|
+
"kelvin",
|
|
91
|
+
"kilogram",
|
|
92
|
+
"long_quantity",
|
|
93
|
+
"long_unit",
|
|
94
|
+
"lumen",
|
|
95
|
+
"lux",
|
|
96
|
+
"metre",
|
|
97
|
+
"mole",
|
|
98
|
+
"newton",
|
|
99
|
+
"ohm",
|
|
100
|
+
"pascal",
|
|
101
|
+
"radian",
|
|
102
|
+
"second",
|
|
103
|
+
"siemens",
|
|
104
|
+
"sievert",
|
|
105
|
+
"steradian",
|
|
106
|
+
"tesla",
|
|
107
|
+
"volt",
|
|
108
|
+
"watt",
|
|
109
|
+
"weber",
|
|
110
|
+
]
|