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.
@@ -1,9 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unit-aware-arithmetic
3
- Version: 1.0.0
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
- - Conversion: `.to(target_unit)`
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
- ## Available Units
125
-
126
- ### Length
127
- - `meter`, `kilometer`, `centimeter`, `millimeter`
128
- - `inch`, `foot`, `yard`, `mile`
129
-
130
- ### Mass
131
- - `kilogram`, `gram`, `milligram`, `tonne`
132
- - `pound`, `ounce`
133
-
134
- ### Time
135
- - `second`, `minute`, `hour`, `day`
136
-
137
- ### Temperature
138
- - `kelvin`, `celsius`, `fahrenheit`
139
-
140
- ### Current
141
- - `ampere`, `milliampere`
142
-
143
- ### Derived Units
144
- - `newton` (force)
145
- - `joule`, `kilojoule` (energy)
146
- - `watt`, `kilowatt` (power)
147
- - `pascal`, `kilopascal` (pressure)
148
- - `meter_per_second`, `kilometer_per_hour` (velocity)
149
- - `meter_per_second_squared` (acceleration)
150
-
151
- ## Error Handling
152
-
153
- The library provides clear error messages for invalid operations:
154
-
155
- ```python
156
- from dimensional import Quantity, units, IncompatibleUnitsError
157
-
158
- distance = Quantity(100, units.meter)
159
- time = Quantity(10, units.second)
160
-
161
- try:
162
- # This will raise IncompatibleUnitsError
163
- result = distance + time
164
- except IncompatibleUnitsError as e:
165
- print(e) # "Cannot add m and s: incompatible dimensions"
166
- ```
167
-
168
- ## Testing
169
-
170
- Run the test suite:
171
-
172
- ```bash
173
- pytest test_dimensional.py -v
174
- ```
175
-
176
- Run with coverage:
177
-
178
- ```bash
179
- pytest test_dimensional.py --cov=dimensional --cov-report=html
180
- ```
181
-
182
- ## Type Checking
183
-
184
- This library includes type hints. Run type checking with:
185
-
186
- ```bash
187
- mypy dimensional.py
188
- ```
189
-
190
- ## Design Principles
191
-
192
- 1. **Zero Dependencies**: Core functionality has no external dependencies
193
- 2. **Type Safety**: Prevents invalid operations at runtime
194
- 3. **Clear Errors**: Actionable error messages
195
- 4. **Production Ready**: Comprehensive test coverage
196
- 5. **Performance**: Efficient implementation with minimal overhead
197
-
198
- ## API Reference
199
-
200
- ### `Dimension`
201
-
202
- Represents the dimensional formula of a unit (e.g., L^1 T^-2 for acceleration).
203
-
204
- ### `Unit`
205
-
206
- Represents a unit of measurement with its dimension and conversion factor.
207
-
208
- ### `Quantity`
209
-
210
- A numeric value with an associated unit. Supports:
211
- - Arithmetic: `+`, `-`, `*`, `/`, `**`, `-` (negation), `abs()`
212
- - Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=`
213
- - Conversion: `.to(target_unit)`
214
-
215
- ### `units`
216
-
217
- Namespace containing all predefined units.
218
-
219
- ## License
220
-
221
- MIT License
222
-
223
- ## Contributing
224
-
225
- Contributions are welcome! Please ensure:
226
- - All tests pass
227
- - Code coverage remains >90%
228
- - Type hints are included
229
- - Documentation is updated
230
-
231
- ## Changelog
232
-
233
- ### 1.0.0 (2026-08-28)
234
- - Initial release
235
- - Support for SI and imperial units
236
- - Comprehensive dimensional analysis
237
- - Temperature conversion with offset handling
238
- - Full test coverage
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