unit-aware-arithmetic 1.0.0__tar.gz → 2.0.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.
- {unit_aware_arithmetic-1.0.0/unit_aware_arithmetic.egg-info → unit_aware_arithmetic-2.0.0}/PKG-INFO +37 -10
- {unit_aware_arithmetic-1.0.0 → unit_aware_arithmetic-2.0.0}/README.md +270 -238
- unit_aware_arithmetic-2.0.0/dimensional.py +584 -0
- {unit_aware_arithmetic-1.0.0 → unit_aware_arithmetic-2.0.0}/pyproject.toml +51 -51
- {unit_aware_arithmetic-1.0.0 → unit_aware_arithmetic-2.0.0/unit_aware_arithmetic.egg-info}/PKG-INFO +37 -10
- {unit_aware_arithmetic-1.0.0 → unit_aware_arithmetic-2.0.0}/unit_aware_arithmetic.egg-info/SOURCES.txt +0 -1
- unit_aware_arithmetic-1.0.0/dimensional.py +0 -364
- unit_aware_arithmetic-1.0.0/setup.py +0 -47
- {unit_aware_arithmetic-1.0.0 → unit_aware_arithmetic-2.0.0}/LICENSE +0 -0
- {unit_aware_arithmetic-1.0.0 → unit_aware_arithmetic-2.0.0}/MANIFEST.in +0 -0
- {unit_aware_arithmetic-1.0.0 → unit_aware_arithmetic-2.0.0}/py.typed +0 -0
- {unit_aware_arithmetic-1.0.0 → unit_aware_arithmetic-2.0.0}/setup.cfg +0 -0
- {unit_aware_arithmetic-1.0.0 → unit_aware_arithmetic-2.0.0}/unit_aware_arithmetic.egg-info/dependency_links.txt +0 -0
- {unit_aware_arithmetic-1.0.0 → unit_aware_arithmetic-2.0.0}/unit_aware_arithmetic.egg-info/requires.txt +0 -0
- {unit_aware_arithmetic-1.0.0 → unit_aware_arithmetic-2.0.0}/unit_aware_arithmetic.egg-info/top_level.txt +0 -0
{unit_aware_arithmetic-1.0.0/unit_aware_arithmetic.egg-info → unit_aware_arithmetic-2.0.0}/PKG-INFO
RENAMED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: unit-aware-arithmetic
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Type-safe dimensional arithmetic library with unit tracking
|
|
5
|
-
Home-page: https://github.com/parthivrawat/unit-aware-arithmetic
|
|
6
|
-
Author: Parthiv Rawat
|
|
7
5
|
Author-email: Parthiv Rawat <parthiv05022000@gmail.com>
|
|
8
6
|
License: MIT License
|
|
9
7
|
|
|
@@ -54,10 +52,7 @@ Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
|
54
52
|
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
55
53
|
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
56
54
|
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
57
|
-
Dynamic: author
|
|
58
|
-
Dynamic: home-page
|
|
59
55
|
Dynamic: license-file
|
|
60
|
-
Dynamic: requires-python
|
|
61
56
|
|
|
62
57
|
# Unit-Aware Arithmetic (Python)
|
|
63
58
|
|
|
@@ -180,6 +175,11 @@ d2 = Quantity(1, units.meter)
|
|
|
180
175
|
# Automatic conversion for comparison
|
|
181
176
|
print(d1 == d2) # True
|
|
182
177
|
print(d1 < Quantity(2, units.meter)) # True
|
|
178
|
+
|
|
179
|
+
# `==` is strict exact equality (after conversion to a common unit).
|
|
180
|
+
# For approximate comparison within a tolerance, use `is_close`:
|
|
181
|
+
print(Quantity(1, units.meter).is_close(Quantity(1.0000001, units.meter), rel_tol=1e-6)) # True
|
|
182
|
+
print(Quantity(0, units.meter).is_close(Quantity(1e-12, units.meter), abs_tol=1e-9)) # True
|
|
183
183
|
```
|
|
184
184
|
|
|
185
185
|
## Available Units
|
|
@@ -201,20 +201,29 @@ print(d1 < Quantity(2, units.meter)) # True
|
|
|
201
201
|
### Current
|
|
202
202
|
- `ampere`, `milliampere`
|
|
203
203
|
|
|
204
|
+
### Chemistry
|
|
205
|
+
- `mole`
|
|
206
|
+
|
|
204
207
|
### Derived Units
|
|
205
208
|
- `newton` (force)
|
|
206
209
|
- `joule`, `kilojoule` (energy)
|
|
210
|
+
- `calorie`, `kilocalorie`, `watt_hour` (energy)
|
|
207
211
|
- `watt`, `kilowatt` (power)
|
|
208
212
|
- `pascal`, `kilopascal` (pressure)
|
|
209
|
-
- `meter_per_second`, `kilometer_per_hour` (velocity)
|
|
213
|
+
- `meter_per_second`, `kilometer_per_hour`, `mile_per_hour` (velocity)
|
|
210
214
|
- `meter_per_second_squared` (acceleration)
|
|
215
|
+
- `square_meter`, `square_kilometer`, `hectare` (area)
|
|
216
|
+
- `cubic_meter`, `liter`, `milliliter` (volume)
|
|
217
|
+
- `hertz`, `kilohertz`, `megahertz` (frequency)
|
|
218
|
+
- `radian`, `degree`, `arcminute`, `arcsecond` (angle)
|
|
219
|
+
- `volt`, `ohm` (electricity)
|
|
211
220
|
|
|
212
221
|
## Error Handling
|
|
213
222
|
|
|
214
223
|
The library provides clear error messages for invalid operations:
|
|
215
224
|
|
|
216
225
|
```python
|
|
217
|
-
from dimensional import Quantity, units, IncompatibleUnitsError
|
|
226
|
+
from dimensional import Quantity, units, IncompatibleUnitsError, AffineUnitArithmeticError
|
|
218
227
|
|
|
219
228
|
distance = Quantity(100, units.meter)
|
|
220
229
|
time = Quantity(10, units.second)
|
|
@@ -224,6 +233,12 @@ try:
|
|
|
224
233
|
result = distance + time
|
|
225
234
|
except IncompatibleUnitsError as e:
|
|
226
235
|
print(e) # "Cannot add m and s: incompatible dimensions"
|
|
236
|
+
|
|
237
|
+
try:
|
|
238
|
+
# This will raise AffineUnitArithmeticError
|
|
239
|
+
result = Quantity(2, units.celsius) * Quantity(3, units.celsius)
|
|
240
|
+
except AffineUnitArithmeticError as e:
|
|
241
|
+
print(e) # "Cannot multiply affine units °C and °C; ..."
|
|
227
242
|
```
|
|
228
243
|
|
|
229
244
|
## Testing
|
|
@@ -270,8 +285,9 @@ Represents a unit of measurement with its dimension and conversion factor.
|
|
|
270
285
|
|
|
271
286
|
A numeric value with an associated unit. Supports:
|
|
272
287
|
- Arithmetic: `+`, `-`, `*`, `/`, `**`, `-` (negation), `abs()`
|
|
273
|
-
- Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=`
|
|
274
|
-
-
|
|
288
|
+
- Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=` (`==` is strict exact equality after conversion to a common unit)
|
|
289
|
+
- Approximate comparison: `.is_close(other, rel_tol=1e-9, abs_tol=0.0)`
|
|
290
|
+
- Conversion: `.to(target_unit)` (returns `Quantity`); `.value_in(target_unit)` (returns the raw `float` value)
|
|
275
291
|
|
|
276
292
|
### `units`
|
|
277
293
|
|
|
@@ -291,6 +307,17 @@ Contributions are welcome! Please ensure:
|
|
|
291
307
|
|
|
292
308
|
## Changelog
|
|
293
309
|
|
|
310
|
+
### 2.0.0 (2026-09-06)
|
|
311
|
+
- Added angle units: `radian`, `degree`, `arcminute`, `arcsecond`
|
|
312
|
+
- Added frequency units: `kilohertz`, `megahertz`
|
|
313
|
+
- Added area units: `square_kilometer`, `hectare`
|
|
314
|
+
- Added volume units: `liter`, `milliliter`
|
|
315
|
+
- Added velocity unit: `mile_per_hour`
|
|
316
|
+
- Added chemistry unit: `mole`
|
|
317
|
+
- Added energy units: `calorie`, `kilocalorie`, `watt_hour`
|
|
318
|
+
- Added electricity units: `volt`, `ohm`
|
|
319
|
+
- Updated canonical-unit lookup table to canonicalize Hz, m², m³, V, and Ω
|
|
320
|
+
|
|
294
321
|
### 1.0.0 (2026-08-28)
|
|
295
322
|
- Initial release
|
|
296
323
|
- Support for SI and imperial units
|
|
@@ -1,238 +1,270 @@
|
|
|
1
|
-
# Unit-Aware Arithmetic (Python)
|
|
2
|
-
|
|
3
|
-
A type-safe dimensional arithmetic library that tracks units at runtime and prevents invalid operations.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- ✅ **Type-safe dimensional analysis**: Prevents incompatible unit operations
|
|
8
|
-
- ✅ **Zero dependencies**: Core functionality has no external dependencies
|
|
9
|
-
- ✅ **Comprehensive unit coverage**: SI, imperial, and derived units
|
|
10
|
-
- ✅ **Arithmetic operations**: Add, subtract, multiply, divide with unit tracking
|
|
11
|
-
- ✅ **Unit conversion**: Automatic and explicit conversion between compatible units
|
|
12
|
-
- ✅ **Clear error messages**: Helpful errors for incompatible operations
|
|
13
|
-
- ✅ **Production-ready**: Comprehensive test coverage (>95%)
|
|
14
|
-
|
|
15
|
-
## Installation
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
pip install -e .
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Quick Start
|
|
22
|
-
|
|
23
|
-
```python
|
|
24
|
-
from dimensional import Quantity, units
|
|
25
|
-
|
|
26
|
-
# Create quantities with units
|
|
27
|
-
distance = Quantity(100, units.meter)
|
|
28
|
-
time = Quantity(9.58, units.second)
|
|
29
|
-
|
|
30
|
-
# Arithmetic operations with automatic unit tracking
|
|
31
|
-
speed = distance / time
|
|
32
|
-
print(speed) # 10.438413361169102 m/s
|
|
33
|
-
|
|
34
|
-
# Unit conversion
|
|
35
|
-
distance_km = distance.to(units.kilometer)
|
|
36
|
-
print(distance_km) # 0.1 km
|
|
37
|
-
|
|
38
|
-
# Type-safe operations - this will raise an error!
|
|
39
|
-
try:
|
|
40
|
-
distance + time # IncompatibleUnitsError
|
|
41
|
-
except Exception as e:
|
|
42
|
-
print(f"Error: {e}")
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Usage Examples
|
|
46
|
-
|
|
47
|
-
### Basic Arithmetic
|
|
48
|
-
|
|
49
|
-
```python
|
|
50
|
-
from dimensional import Quantity, units
|
|
51
|
-
|
|
52
|
-
# Addition (same dimension required)
|
|
53
|
-
d1 = Quantity(5, units.meter)
|
|
54
|
-
d2 = Quantity(3, units.meter)
|
|
55
|
-
total = d1 + d2 # 8.0 m
|
|
56
|
-
|
|
57
|
-
# Multiplication creates derived units
|
|
58
|
-
area = Quantity(5, units.meter) * Quantity(3, units.meter)
|
|
59
|
-
print(area) # 15.0 m·m
|
|
60
|
-
|
|
61
|
-
# Division creates derived units
|
|
62
|
-
velocity = Quantity(100, units.meter) / Quantity(10, units.second)
|
|
63
|
-
print(velocity) # 10.0 m/s
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Unit Conversion
|
|
67
|
-
|
|
68
|
-
```python
|
|
69
|
-
from dimensional import Quantity, units
|
|
70
|
-
|
|
71
|
-
# Length conversion
|
|
72
|
-
distance = Quantity(1, units.mile)
|
|
73
|
-
distance_km = distance.to(units.kilometer)
|
|
74
|
-
print(distance_km) # 1.60934 km
|
|
75
|
-
|
|
76
|
-
# Temperature conversion
|
|
77
|
-
temp_c = Quantity(0, units.celsius)
|
|
78
|
-
temp_k = temp_c.to(units.kelvin)
|
|
79
|
-
print(temp_k) # 273.15 K
|
|
80
|
-
|
|
81
|
-
# Mass conversion
|
|
82
|
-
mass_lb = Quantity(10, units.pound)
|
|
83
|
-
mass_kg = mass_lb.to(units.kilogram)
|
|
84
|
-
print(mass_kg) # 4.53592 kg
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### Physics Calculations
|
|
88
|
-
|
|
89
|
-
```python
|
|
90
|
-
from dimensional import Quantity, units
|
|
91
|
-
|
|
92
|
-
# Calculate velocity
|
|
93
|
-
distance = Quantity(100, units.meter)
|
|
94
|
-
time = Quantity(9.58, units.second)
|
|
95
|
-
velocity = distance / time
|
|
96
|
-
print(f"Velocity: {velocity}")
|
|
97
|
-
|
|
98
|
-
# Calculate force (F = ma)
|
|
99
|
-
mass = Quantity(10, units.kilogram)
|
|
100
|
-
acceleration = Quantity(9.8, units.meter_per_second_squared)
|
|
101
|
-
force = mass * acceleration
|
|
102
|
-
print(f"Force: {force}")
|
|
103
|
-
|
|
104
|
-
# Calculate kinetic energy (KE = 1/2 * m * v²)
|
|
105
|
-
mass = Quantity(2, units.kilogram)
|
|
106
|
-
velocity = Quantity(10, units.meter_per_second)
|
|
107
|
-
ke = 0.5 * mass * (velocity ** 2)
|
|
108
|
-
print(f"Kinetic Energy: {ke}")
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### Comparison Operations
|
|
112
|
-
|
|
113
|
-
```python
|
|
114
|
-
from dimensional import Quantity, units
|
|
115
|
-
|
|
116
|
-
d1 = Quantity(100, units.centimeter)
|
|
117
|
-
d2 = Quantity(1, units.meter)
|
|
118
|
-
|
|
119
|
-
# Automatic conversion for comparison
|
|
120
|
-
print(d1 == d2) # True
|
|
121
|
-
print(d1 < Quantity(2, units.meter)) # True
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
- `
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
- `
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
- `
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
1
|
+
# Unit-Aware Arithmetic (Python)
|
|
2
|
+
|
|
3
|
+
A type-safe dimensional arithmetic library that tracks units at runtime and prevents invalid operations.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ **Type-safe dimensional analysis**: Prevents incompatible unit operations
|
|
8
|
+
- ✅ **Zero dependencies**: Core functionality has no external dependencies
|
|
9
|
+
- ✅ **Comprehensive unit coverage**: SI, imperial, and derived units
|
|
10
|
+
- ✅ **Arithmetic operations**: Add, subtract, multiply, divide with unit tracking
|
|
11
|
+
- ✅ **Unit conversion**: Automatic and explicit conversion between compatible units
|
|
12
|
+
- ✅ **Clear error messages**: Helpful errors for incompatible operations
|
|
13
|
+
- ✅ **Production-ready**: Comprehensive test coverage (>95%)
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install -e .
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from dimensional import Quantity, units
|
|
25
|
+
|
|
26
|
+
# Create quantities with units
|
|
27
|
+
distance = Quantity(100, units.meter)
|
|
28
|
+
time = Quantity(9.58, units.second)
|
|
29
|
+
|
|
30
|
+
# Arithmetic operations with automatic unit tracking
|
|
31
|
+
speed = distance / time
|
|
32
|
+
print(speed) # 10.438413361169102 m/s
|
|
33
|
+
|
|
34
|
+
# Unit conversion
|
|
35
|
+
distance_km = distance.to(units.kilometer)
|
|
36
|
+
print(distance_km) # 0.1 km
|
|
37
|
+
|
|
38
|
+
# Type-safe operations - this will raise an error!
|
|
39
|
+
try:
|
|
40
|
+
distance + time # IncompatibleUnitsError
|
|
41
|
+
except Exception as e:
|
|
42
|
+
print(f"Error: {e}")
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage Examples
|
|
46
|
+
|
|
47
|
+
### Basic Arithmetic
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from dimensional import Quantity, units
|
|
51
|
+
|
|
52
|
+
# Addition (same dimension required)
|
|
53
|
+
d1 = Quantity(5, units.meter)
|
|
54
|
+
d2 = Quantity(3, units.meter)
|
|
55
|
+
total = d1 + d2 # 8.0 m
|
|
56
|
+
|
|
57
|
+
# Multiplication creates derived units
|
|
58
|
+
area = Quantity(5, units.meter) * Quantity(3, units.meter)
|
|
59
|
+
print(area) # 15.0 m·m
|
|
60
|
+
|
|
61
|
+
# Division creates derived units
|
|
62
|
+
velocity = Quantity(100, units.meter) / Quantity(10, units.second)
|
|
63
|
+
print(velocity) # 10.0 m/s
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Unit Conversion
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from dimensional import Quantity, units
|
|
70
|
+
|
|
71
|
+
# Length conversion
|
|
72
|
+
distance = Quantity(1, units.mile)
|
|
73
|
+
distance_km = distance.to(units.kilometer)
|
|
74
|
+
print(distance_km) # 1.60934 km
|
|
75
|
+
|
|
76
|
+
# Temperature conversion
|
|
77
|
+
temp_c = Quantity(0, units.celsius)
|
|
78
|
+
temp_k = temp_c.to(units.kelvin)
|
|
79
|
+
print(temp_k) # 273.15 K
|
|
80
|
+
|
|
81
|
+
# Mass conversion
|
|
82
|
+
mass_lb = Quantity(10, units.pound)
|
|
83
|
+
mass_kg = mass_lb.to(units.kilogram)
|
|
84
|
+
print(mass_kg) # 4.53592 kg
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Physics Calculations
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from dimensional import Quantity, units
|
|
91
|
+
|
|
92
|
+
# Calculate velocity
|
|
93
|
+
distance = Quantity(100, units.meter)
|
|
94
|
+
time = Quantity(9.58, units.second)
|
|
95
|
+
velocity = distance / time
|
|
96
|
+
print(f"Velocity: {velocity}")
|
|
97
|
+
|
|
98
|
+
# Calculate force (F = ma)
|
|
99
|
+
mass = Quantity(10, units.kilogram)
|
|
100
|
+
acceleration = Quantity(9.8, units.meter_per_second_squared)
|
|
101
|
+
force = mass * acceleration
|
|
102
|
+
print(f"Force: {force}")
|
|
103
|
+
|
|
104
|
+
# Calculate kinetic energy (KE = 1/2 * m * v²)
|
|
105
|
+
mass = Quantity(2, units.kilogram)
|
|
106
|
+
velocity = Quantity(10, units.meter_per_second)
|
|
107
|
+
ke = 0.5 * mass * (velocity ** 2)
|
|
108
|
+
print(f"Kinetic Energy: {ke}")
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Comparison Operations
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from dimensional import Quantity, units
|
|
115
|
+
|
|
116
|
+
d1 = Quantity(100, units.centimeter)
|
|
117
|
+
d2 = Quantity(1, units.meter)
|
|
118
|
+
|
|
119
|
+
# Automatic conversion for comparison
|
|
120
|
+
print(d1 == d2) # True
|
|
121
|
+
print(d1 < Quantity(2, units.meter)) # True
|
|
122
|
+
|
|
123
|
+
# `==` is strict exact equality (after conversion to a common unit).
|
|
124
|
+
# For approximate comparison within a tolerance, use `is_close`:
|
|
125
|
+
print(Quantity(1, units.meter).is_close(Quantity(1.0000001, units.meter), rel_tol=1e-6)) # True
|
|
126
|
+
print(Quantity(0, units.meter).is_close(Quantity(1e-12, units.meter), abs_tol=1e-9)) # True
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Available Units
|
|
130
|
+
|
|
131
|
+
### Length
|
|
132
|
+
- `meter`, `kilometer`, `centimeter`, `millimeter`
|
|
133
|
+
- `inch`, `foot`, `yard`, `mile`
|
|
134
|
+
|
|
135
|
+
### Mass
|
|
136
|
+
- `kilogram`, `gram`, `milligram`, `tonne`
|
|
137
|
+
- `pound`, `ounce`
|
|
138
|
+
|
|
139
|
+
### Time
|
|
140
|
+
- `second`, `minute`, `hour`, `day`
|
|
141
|
+
|
|
142
|
+
### Temperature
|
|
143
|
+
- `kelvin`, `celsius`, `fahrenheit`
|
|
144
|
+
|
|
145
|
+
### Current
|
|
146
|
+
- `ampere`, `milliampere`
|
|
147
|
+
|
|
148
|
+
### Chemistry
|
|
149
|
+
- `mole`
|
|
150
|
+
|
|
151
|
+
### Derived Units
|
|
152
|
+
- `newton` (force)
|
|
153
|
+
- `joule`, `kilojoule` (energy)
|
|
154
|
+
- `calorie`, `kilocalorie`, `watt_hour` (energy)
|
|
155
|
+
- `watt`, `kilowatt` (power)
|
|
156
|
+
- `pascal`, `kilopascal` (pressure)
|
|
157
|
+
- `meter_per_second`, `kilometer_per_hour`, `mile_per_hour` (velocity)
|
|
158
|
+
- `meter_per_second_squared` (acceleration)
|
|
159
|
+
- `square_meter`, `square_kilometer`, `hectare` (area)
|
|
160
|
+
- `cubic_meter`, `liter`, `milliliter` (volume)
|
|
161
|
+
- `hertz`, `kilohertz`, `megahertz` (frequency)
|
|
162
|
+
- `radian`, `degree`, `arcminute`, `arcsecond` (angle)
|
|
163
|
+
- `volt`, `ohm` (electricity)
|
|
164
|
+
|
|
165
|
+
## Error Handling
|
|
166
|
+
|
|
167
|
+
The library provides clear error messages for invalid operations:
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from dimensional import Quantity, units, IncompatibleUnitsError, AffineUnitArithmeticError
|
|
171
|
+
|
|
172
|
+
distance = Quantity(100, units.meter)
|
|
173
|
+
time = Quantity(10, units.second)
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
# This will raise IncompatibleUnitsError
|
|
177
|
+
result = distance + time
|
|
178
|
+
except IncompatibleUnitsError as e:
|
|
179
|
+
print(e) # "Cannot add m and s: incompatible dimensions"
|
|
180
|
+
|
|
181
|
+
try:
|
|
182
|
+
# This will raise AffineUnitArithmeticError
|
|
183
|
+
result = Quantity(2, units.celsius) * Quantity(3, units.celsius)
|
|
184
|
+
except AffineUnitArithmeticError as e:
|
|
185
|
+
print(e) # "Cannot multiply affine units °C and °C; ..."
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Testing
|
|
189
|
+
|
|
190
|
+
Run the test suite:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
pytest test_dimensional.py -v
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Run with coverage:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
pytest test_dimensional.py --cov=dimensional --cov-report=html
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Type Checking
|
|
203
|
+
|
|
204
|
+
This library includes type hints. Run type checking with:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
mypy dimensional.py
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Design Principles
|
|
211
|
+
|
|
212
|
+
1. **Zero Dependencies**: Core functionality has no external dependencies
|
|
213
|
+
2. **Type Safety**: Prevents invalid operations at runtime
|
|
214
|
+
3. **Clear Errors**: Actionable error messages
|
|
215
|
+
4. **Production Ready**: Comprehensive test coverage
|
|
216
|
+
5. **Performance**: Efficient implementation with minimal overhead
|
|
217
|
+
|
|
218
|
+
## API Reference
|
|
219
|
+
|
|
220
|
+
### `Dimension`
|
|
221
|
+
|
|
222
|
+
Represents the dimensional formula of a unit (e.g., L^1 T^-2 for acceleration).
|
|
223
|
+
|
|
224
|
+
### `Unit`
|
|
225
|
+
|
|
226
|
+
Represents a unit of measurement with its dimension and conversion factor.
|
|
227
|
+
|
|
228
|
+
### `Quantity`
|
|
229
|
+
|
|
230
|
+
A numeric value with an associated unit. Supports:
|
|
231
|
+
- Arithmetic: `+`, `-`, `*`, `/`, `**`, `-` (negation), `abs()`
|
|
232
|
+
- Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=` (`==` is strict exact equality after conversion to a common unit)
|
|
233
|
+
- Approximate comparison: `.is_close(other, rel_tol=1e-9, abs_tol=0.0)`
|
|
234
|
+
- Conversion: `.to(target_unit)` (returns `Quantity`); `.value_in(target_unit)` (returns the raw `float` value)
|
|
235
|
+
|
|
236
|
+
### `units`
|
|
237
|
+
|
|
238
|
+
Namespace containing all predefined units.
|
|
239
|
+
|
|
240
|
+
## License
|
|
241
|
+
|
|
242
|
+
MIT License
|
|
243
|
+
|
|
244
|
+
## Contributing
|
|
245
|
+
|
|
246
|
+
Contributions are welcome! Please ensure:
|
|
247
|
+
- All tests pass
|
|
248
|
+
- Code coverage remains >90%
|
|
249
|
+
- Type hints are included
|
|
250
|
+
- Documentation is updated
|
|
251
|
+
|
|
252
|
+
## Changelog
|
|
253
|
+
|
|
254
|
+
### 2.0.0 (2026-09-06)
|
|
255
|
+
- Added angle units: `radian`, `degree`, `arcminute`, `arcsecond`
|
|
256
|
+
- Added frequency units: `kilohertz`, `megahertz`
|
|
257
|
+
- Added area units: `square_kilometer`, `hectare`
|
|
258
|
+
- Added volume units: `liter`, `milliliter`
|
|
259
|
+
- Added velocity unit: `mile_per_hour`
|
|
260
|
+
- Added chemistry unit: `mole`
|
|
261
|
+
- Added energy units: `calorie`, `kilocalorie`, `watt_hour`
|
|
262
|
+
- Added electricity units: `volt`, `ohm`
|
|
263
|
+
- Updated canonical-unit lookup table to canonicalize Hz, m², m³, V, and Ω
|
|
264
|
+
|
|
265
|
+
### 1.0.0 (2026-08-28)
|
|
266
|
+
- Initial release
|
|
267
|
+
- Support for SI and imperial units
|
|
268
|
+
- Comprehensive dimensional analysis
|
|
269
|
+
- Temperature conversion with offset handling
|
|
270
|
+
- Full test coverage
|