python-units 0.2.0__py3-none-any.whl → 0.4.0__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.
api/public.py CHANGED
@@ -5,20 +5,40 @@ from api.si import (
5
5
  ampere,
6
6
  becquerel,
7
7
  candela,
8
+ centimetre,
8
9
  coulomb,
9
10
  degree_celcius,
10
11
  farad,
12
+ gram,
11
13
  gray,
12
14
  henry,
13
15
  hertz,
16
+ hour,
14
17
  joule,
15
18
  katal,
16
19
  kelvin,
17
20
  kilogram,
21
+ kiloampere,
22
+ kilometre,
23
+ kilovolt,
24
+ kilowatt,
18
25
  lumen,
19
26
  lux,
27
+ megawatt,
20
28
  metre,
29
+ microgram,
30
+ micrometre,
31
+ microsecond,
32
+ milliampere,
33
+ milligram,
34
+ millimetre,
35
+ millisecond,
36
+ millivolt,
37
+ milliwatt,
38
+ minute,
21
39
  mole,
40
+ nanometre,
41
+ nanosecond,
22
42
  newton,
23
43
  ohm,
24
44
  pascal,
@@ -28,6 +48,7 @@ from api.si import (
28
48
  sievert,
29
49
  steradian,
30
50
  tesla,
51
+ tonne,
31
52
  volt,
32
53
  watt,
33
54
  weber,
@@ -43,16 +64,21 @@ from core.quantity import (
43
64
  Quantity,
44
65
  complex_quantity,
45
66
  complex_unit,
67
+ convert,
46
68
  float_quantity,
47
69
  float_unit,
48
70
  int_quantity,
49
71
  int_unit,
50
72
  long_quantity,
51
73
  long_unit,
74
+ multiplier,
75
+ unit,
76
+ value,
52
77
  )
53
78
  from core.unit_definitions import BaseUnit, CustomUnitBase, DerivedUnit, SIUnit
54
79
  from models.dimension import Dimension, DimensionSystem
55
80
 
81
+
56
82
  Unit = Quantity
57
83
 
58
84
  __all__ = [
@@ -72,28 +98,50 @@ __all__ = [
72
98
  "ampere",
73
99
  "becquerel",
74
100
  "candela",
101
+ "centimetre",
75
102
  "complex_quantity",
76
103
  "complex_unit",
104
+ "convert",
77
105
  "coulomb",
78
106
  "degree_celcius",
79
107
  "farad",
80
108
  "float_quantity",
81
109
  "float_unit",
110
+ "gram",
82
111
  "gray",
83
112
  "henry",
84
113
  "hertz",
114
+ "hour",
85
115
  "int_quantity",
86
116
  "int_unit",
87
117
  "joule",
88
118
  "katal",
89
119
  "kelvin",
90
120
  "kilogram",
121
+ "kiloampere",
122
+ "kilometre",
123
+ "kilovolt",
124
+ "kilowatt",
91
125
  "long_quantity",
92
126
  "long_unit",
93
127
  "lumen",
94
128
  "lux",
129
+ "megawatt",
95
130
  "metre",
131
+ "microgram",
132
+ "micrometre",
133
+ "microsecond",
134
+ "milliampere",
135
+ "milligram",
136
+ "millimetre",
137
+ "millisecond",
138
+ "millivolt",
139
+ "milliwatt",
140
+ "minute",
141
+ "multiplier",
96
142
  "mole",
143
+ "nanometre",
144
+ "nanosecond",
97
145
  "newton",
98
146
  "ohm",
99
147
  "pascal",
@@ -103,6 +151,9 @@ __all__ = [
103
151
  "sievert",
104
152
  "steradian",
105
153
  "tesla",
154
+ "tonne",
155
+ "unit",
156
+ "value",
106
157
  "volt",
107
158
  "watt",
108
159
  "weber",
api/si.py CHANGED
@@ -29,7 +29,11 @@ siemens = DerivedUnit.define("S", ampere / volt)
29
29
  weber = DerivedUnit.define("Wb", volt * second)
30
30
  tesla = DerivedUnit.define("T", weber / metre / metre)
31
31
  henry = DerivedUnit.define("H", weber / ampere)
32
- degree_celcius = DerivedUnit.define("°C", kelvin)
32
+ degree_celcius = DerivedUnit.define(
33
+ "°C",
34
+ kelvin,
35
+ supports_multiplicative_conversion=False,
36
+ )
33
37
  lumen = DerivedUnit.define("lm", candela * steradian)
34
38
  lux = DerivedUnit.define("lx", lumen / metre / metre)
35
39
  becquerel = DerivedUnit.define("Bq", SIUnit() / second)
@@ -37,6 +41,31 @@ gray = DerivedUnit.define("Gy", joule / kilogram)
37
41
  sievert = DerivedUnit.define("Sv", joule / kilogram)
38
42
  katal = DerivedUnit.define("kat", mole / second)
39
43
 
44
+ kilometre = DerivedUnit.define("km", metre, conversion_factor=1000.0)
45
+ centimetre = DerivedUnit.define("cm", metre, conversion_factor=0.01)
46
+ millimetre = DerivedUnit.define("mm", metre, conversion_factor=0.001)
47
+ micrometre = DerivedUnit.define("µm", metre, conversion_factor=0.000001)
48
+ nanometre = DerivedUnit.define("nm", metre, conversion_factor=0.000000001)
49
+
50
+ gram = DerivedUnit.define("g", kilogram, conversion_factor=0.001)
51
+ milligram = DerivedUnit.define("mg", kilogram, conversion_factor=0.000001)
52
+ microgram = DerivedUnit.define("µg", kilogram, conversion_factor=0.000000001)
53
+ tonne = DerivedUnit.define("t", kilogram, conversion_factor=1000.0)
54
+
55
+ minute = DerivedUnit.define("min", second, conversion_factor=60.0)
56
+ hour = DerivedUnit.define("h", second, conversion_factor=3600.0)
57
+ millisecond = DerivedUnit.define("ms", second, conversion_factor=0.001)
58
+ microsecond = DerivedUnit.define("µs", second, conversion_factor=0.000001)
59
+ nanosecond = DerivedUnit.define("ns", second, conversion_factor=0.000000001)
60
+
61
+ milliampere = DerivedUnit.define("mA", ampere, conversion_factor=0.001)
62
+ kiloampere = DerivedUnit.define("kA", ampere, conversion_factor=1000.0)
63
+ millivolt = DerivedUnit.define("mV", volt, conversion_factor=0.001)
64
+ kilovolt = DerivedUnit.define("kV", volt, conversion_factor=1000.0)
65
+ milliwatt = DerivedUnit.define("mW", watt, conversion_factor=0.001)
66
+ kilowatt = DerivedUnit.define("kW", watt, conversion_factor=1000.0)
67
+ megawatt = DerivedUnit.define("MW", watt, conversion_factor=1000000.0)
68
+
40
69
  for unit in (
41
70
  newton,
42
71
  pascal,
@@ -59,20 +88,40 @@ __all__ = [
59
88
  "ampere",
60
89
  "becquerel",
61
90
  "candela",
91
+ "centimetre",
62
92
  "coulomb",
63
93
  "degree_celcius",
64
94
  "farad",
95
+ "gram",
65
96
  "gray",
66
97
  "henry",
67
98
  "hertz",
99
+ "hour",
68
100
  "joule",
69
101
  "katal",
70
102
  "kelvin",
71
103
  "kilogram",
104
+ "kiloampere",
105
+ "kilometre",
106
+ "kilovolt",
107
+ "kilowatt",
72
108
  "lumen",
73
109
  "lux",
110
+ "megawatt",
74
111
  "metre",
112
+ "microgram",
113
+ "micrometre",
114
+ "microsecond",
115
+ "milliampere",
116
+ "milligram",
117
+ "millimetre",
118
+ "millisecond",
119
+ "millivolt",
120
+ "milliwatt",
121
+ "minute",
75
122
  "mole",
123
+ "nanometre",
124
+ "nanosecond",
76
125
  "newton",
77
126
  "ohm",
78
127
  "pascal",
@@ -82,6 +131,7 @@ __all__ = [
82
131
  "sievert",
83
132
  "steradian",
84
133
  "tesla",
134
+ "tonne",
85
135
  "volt",
86
136
  "watt",
87
137
  "weber",
core/__init__.py CHANGED
@@ -11,12 +11,16 @@ from .quantity import (
11
11
  Quantity,
12
12
  complex_quantity,
13
13
  complex_unit,
14
+ convert,
14
15
  float_quantity,
15
16
  float_unit,
16
17
  int_quantity,
17
18
  int_unit,
18
19
  long_quantity,
19
20
  long_unit,
21
+ multiplier,
22
+ unit,
23
+ value,
20
24
  )
21
25
  from .unit_definitions import BaseUnit, CustomUnitBase, DerivedUnit, SIUnit
22
26
 
@@ -33,10 +37,14 @@ __all__ = [
33
37
  "UnitsError",
34
38
  "complex_quantity",
35
39
  "complex_unit",
40
+ "convert",
36
41
  "float_quantity",
37
42
  "float_unit",
38
43
  "int_quantity",
39
44
  "int_unit",
40
45
  "long_quantity",
41
46
  "long_unit",
47
+ "multiplier",
48
+ "unit",
49
+ "value",
42
50
  ]
core/deprecations.py ADDED
@@ -0,0 +1,62 @@
1
+ # -*- coding: utf-8 -*-
2
+ """Deprecation helpers for compatibility APIs."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import warnings
7
+ from collections.abc import Callable
8
+ from typing import TypeVar
9
+
10
+
11
+ _T = TypeVar("_T")
12
+
13
+
14
+ def warn_legacy_api(name: str, replacement: str, removal_version: str) -> None:
15
+ """
16
+ Emit a deprecation warning for a legacy public API.
17
+
18
+ Args:
19
+ name: Deprecated API name.
20
+ replacement: Preferred API name or usage pattern.
21
+ removal_version: Planned removal release.
22
+
23
+ Returns:
24
+ None.
25
+
26
+ Raises:
27
+ None.
28
+ """
29
+ warnings.warn(
30
+ "{} is deprecated; use {} instead. It is scheduled for removal in {}.".format(
31
+ name,
32
+ replacement,
33
+ removal_version,
34
+ ),
35
+ DeprecationWarning,
36
+ stacklevel=4,
37
+ )
38
+
39
+
40
+ def deprecated_call(
41
+ name: str,
42
+ replacement: str,
43
+ removal_version: str,
44
+ callback: Callable[[], _T],
45
+ ) -> _T:
46
+ """
47
+ Warn for a deprecated API call and return the callback result.
48
+
49
+ Args:
50
+ name: Deprecated API name.
51
+ replacement: Preferred API name or usage pattern.
52
+ removal_version: Planned removal release.
53
+ callback: Zero-argument callable that performs the actual work.
54
+
55
+ Returns:
56
+ The callback result.
57
+
58
+ Raises:
59
+ Any exception raised by ``callback``.
60
+ """
61
+ warn_legacy_api(name, replacement, removal_version)
62
+ return callback()
core/quantity.py CHANGED
@@ -3,8 +3,15 @@
3
3
 
4
4
  from __future__ import annotations
5
5
 
6
+ from core.deprecations import deprecated_call
6
7
  from core.errors import InvalidValueError, UnitCompatibilityError, UnitOperandError
7
- from core.unit_definitions import BaseUnit, SIUnit, clone_unit
8
+ from core.unit_definitions import (
9
+ BaseUnit,
10
+ DerivedUnit,
11
+ SIUnit,
12
+ clone_unit,
13
+ require_unit_instance,
14
+ )
8
15
  from models.dimension import SI_DIMENSION_SYSTEM
9
16
  from utils.numbers import Scalar, is_number, is_real_number, validate_numeric_value
10
17
 
@@ -17,6 +24,49 @@ def require_quantity_operand(operand: object, operation: str) -> None:
17
24
  )
18
25
 
19
26
 
27
+ def normalize_scalar(value: Scalar) -> Scalar:
28
+ """Return ``int`` for exact integer floats, otherwise return ``value``."""
29
+ if isinstance(value, float) and value.is_integer():
30
+ return int(value)
31
+ return value
32
+
33
+
34
+ def normalize_product(value: Scalar, left: Scalar, right: Scalar) -> Scalar:
35
+ """Normalize exact integer products only when both inputs were integers."""
36
+ if isinstance(left, int) and isinstance(right, int):
37
+ return normalize_scalar(value)
38
+ return value
39
+
40
+
41
+ def normalize_reverse_floor(value: Scalar, denominator: "Quantity") -> Scalar:
42
+ """Preserve legacy int display for unscaled integer reverse floor division."""
43
+ if (
44
+ denominator.unit.conversion_factor == 1.0
45
+ and isinstance(denominator.value, int)
46
+ ):
47
+ return normalize_scalar(value)
48
+ return value
49
+
50
+
51
+ def normalize_result_unit(result_unit: BaseUnit) -> BaseUnit:
52
+ """Return a renderable result unit with no hidden anonymous scale."""
53
+ if isinstance(result_unit, DerivedUnit) or result_unit.conversion_factor == 1.0:
54
+ return result_unit
55
+ try:
56
+ return result_unit.__class__(
57
+ dimension=result_unit.dimension,
58
+ supports_multiplicative_conversion=(
59
+ result_unit.supports_multiplicative_conversion
60
+ ),
61
+ )
62
+ except TypeError:
63
+ unit = result_unit.__class__(dimension=result_unit.dimension)
64
+ unit._supports_multiplicative_conversion = (
65
+ result_unit.supports_multiplicative_conversion
66
+ )
67
+ return unit
68
+
69
+
20
70
  class Quantity:
21
71
  """A numeric value coupled to a unit definition."""
22
72
 
@@ -80,6 +130,44 @@ class Quantity:
80
130
  "unsupported scalar for {}: {}".format(operation, type(value).__name__)
81
131
  )
82
132
 
133
+ def _base_value(self) -> Scalar:
134
+ return self.value * self.unit.conversion_factor
135
+
136
+ def to(self, target_unit: BaseUnit) -> "Quantity":
137
+ """
138
+ Convert this quantity to a compatible scale-only target unit.
139
+
140
+ Args:
141
+ target_unit: Unit definition with the same dimension.
142
+
143
+ Returns:
144
+ Quantity expressed in ``target_unit``.
145
+
146
+ Raises:
147
+ InvalidUnitError: If ``target_unit`` is not a unit definition.
148
+ UnitCompatibilityError: If dimensions differ or either unit cannot
149
+ be converted with a multiplicative scale factor.
150
+ """
151
+ require_unit_instance(target_unit)
152
+ if self.unit.dimension != target_unit.dimension:
153
+ raise UnitCompatibilityError(
154
+ "cannot convert {} to {}".format(self.unit, target_unit)
155
+ )
156
+ if (
157
+ not self.unit.supports_multiplicative_conversion
158
+ or not target_unit.supports_multiplicative_conversion
159
+ ):
160
+ raise UnitCompatibilityError(
161
+ "units require a non-multiplicative conversion: {} and {}".format(
162
+ self.unit,
163
+ target_unit,
164
+ )
165
+ )
166
+ return self.__class__(
167
+ normalize_scalar(self._base_value() / target_unit.conversion_factor),
168
+ target_unit,
169
+ )
170
+
83
171
  def __add__(self, quantity2: object) -> "Quantity":
84
172
  self._require_compatible_quantity(quantity2, "addition")
85
173
  return self.__class__(self.value + quantity2.value, self.unit)
@@ -97,9 +185,22 @@ class Quantity:
97
185
 
98
186
  def __mul__(self, quantity2: object) -> "Quantity":
99
187
  if isinstance(quantity2, Quantity):
100
- return self.__class__(self.value * quantity2.value, self.unit * quantity2.unit)
188
+ result_unit = self.unit * quantity2.unit
189
+ result_value = self._base_value() * quantity2._base_value()
190
+ return self.__class__(
191
+ normalize_product(result_value, self.value, quantity2.value),
192
+ normalize_result_unit(result_unit),
193
+ )
101
194
  if isinstance(quantity2, BaseUnit):
102
- return self.__class__(self.value, self.unit * quantity2)
195
+ result_unit = self.unit * quantity2
196
+ result_value = (
197
+ self._base_value()
198
+ * quantity2.conversion_factor
199
+ )
200
+ return self.__class__(
201
+ normalize_scalar(result_value),
202
+ normalize_result_unit(result_unit),
203
+ )
103
204
  self._require_numeric_scalar(quantity2, "multiplication")
104
205
  return self.__class__(self.value * quantity2, self.unit)
105
206
 
@@ -108,29 +209,55 @@ class Quantity:
108
209
 
109
210
  def __truediv__(self, quantity2: object) -> "Quantity":
110
211
  if isinstance(quantity2, Quantity):
111
- return self.__class__(self.value / quantity2.value, self.unit / quantity2.unit)
212
+ result_unit = self.unit / quantity2.unit
213
+ result_value = self._base_value() / quantity2._base_value()
214
+ return self.__class__(result_value, normalize_result_unit(result_unit))
112
215
  if isinstance(quantity2, BaseUnit):
113
- return self.__class__(self.value, self.unit / quantity2)
216
+ result_unit = self.unit / quantity2
217
+ result_value = (
218
+ self._base_value()
219
+ / quantity2.conversion_factor
220
+ )
221
+ return self.__class__(
222
+ normalize_scalar(result_value),
223
+ normalize_result_unit(result_unit),
224
+ )
114
225
  self._require_numeric_scalar(quantity2, "division")
115
226
  return self.__class__(self.value / quantity2, self.unit)
116
227
 
117
228
  def __rtruediv__(self, quantity2: object) -> "Quantity":
118
229
  if isinstance(quantity2, Quantity):
119
- return self.__class__(quantity2.value / self.value, quantity2.unit / self.unit)
230
+ result_unit = quantity2.unit / self.unit
231
+ result_value = quantity2._base_value() / self._base_value()
232
+ return self.__class__(result_value, normalize_result_unit(result_unit))
120
233
  self._require_numeric_scalar(quantity2, "division")
121
- return self.__class__(quantity2 / self.value, self._dimensionless_unit() / self.unit)
234
+ result_unit = self._dimensionless_unit() / self.unit
235
+ result_value = quantity2 / self._base_value()
236
+ return self.__class__(result_value, normalize_result_unit(result_unit))
122
237
 
123
238
  def __floordiv__(self, quantity2: object) -> "Quantity":
124
239
  if isinstance(quantity2, Quantity):
125
- return self.__class__(self.value // quantity2.value, self.unit / quantity2.unit)
240
+ result_unit = self.unit / quantity2.unit
241
+ result_value = self._base_value() // quantity2._base_value()
242
+ return self.__class__(result_value, normalize_result_unit(result_unit))
126
243
  self._require_real_scalar(quantity2, "floor division")
127
244
  return self.__class__(self.value // quantity2, self.unit)
128
245
 
129
246
  def __rfloordiv__(self, quantity2: object) -> "Quantity":
130
247
  if isinstance(quantity2, Quantity):
131
- return self.__class__(quantity2.value // self.value, quantity2.unit / self.unit)
248
+ result_unit = quantity2.unit / self.unit
249
+ result_value = quantity2._base_value() // self._base_value()
250
+ return self.__class__(
251
+ normalize_scalar(result_value),
252
+ normalize_result_unit(result_unit),
253
+ )
132
254
  self._require_real_scalar(quantity2, "floor division")
133
- return self.__class__(quantity2 // self.value, self._dimensionless_unit() / self.unit)
255
+ result_unit = self._dimensionless_unit() / self.unit
256
+ result_value = quantity2 // self._base_value()
257
+ return self.__class__(
258
+ normalize_reverse_floor(result_value, self),
259
+ normalize_result_unit(result_unit),
260
+ )
134
261
 
135
262
  def __mod__(self, quantity2: object) -> "Quantity":
136
263
  if isinstance(quantity2, Quantity):
@@ -144,7 +271,12 @@ class Quantity:
144
271
  self._require_compatible_quantity(quantity2, "modulo")
145
272
  return self.__class__(quantity2.value % self.value, self.unit)
146
273
  self._require_real_scalar(quantity2, "modulo")
147
- return self.__class__(quantity2 % self.value, self._dimensionless_unit() / self.unit)
274
+ result_unit = self._dimensionless_unit() / self.unit
275
+ result_value = quantity2 % self._base_value()
276
+ return self.__class__(
277
+ normalize_scalar(result_value),
278
+ normalize_result_unit(result_unit),
279
+ )
148
280
 
149
281
  def __divmod__(self, quantity2: object) -> tuple["Quantity", "Quantity"]:
150
282
  return self.__floordiv__(quantity2), self.__mod__(quantity2)
@@ -162,7 +294,12 @@ class Quantity:
162
294
  )
163
295
  if self.is_unitless:
164
296
  return self.__class__(self.value ** exponent, self.unit)
165
- return self.__class__(self.value ** exponent, self.unit ** exponent)
297
+ result_unit = self.unit ** exponent
298
+ result_value = self._base_value() ** exponent
299
+ return self.__class__(
300
+ normalize_scalar(result_value),
301
+ normalize_result_unit(result_unit),
302
+ )
166
303
 
167
304
  def __neg__(self) -> "Quantity":
168
305
  return self.__class__(-self.value, self.unit)
@@ -200,8 +337,12 @@ def float_quantity(quantity: Quantity) -> Quantity:
200
337
 
201
338
  def long_quantity(quantity: Quantity) -> Quantity:
202
339
  """Legacy compatibility helper equivalent to ``int_quantity``."""
203
- require_quantity_operand(quantity, "long conversion")
204
- return Quantity(int(quantity.value), quantity.unit)
340
+ return deprecated_call(
341
+ "long_quantity",
342
+ "int_quantity",
343
+ "1.0.0",
344
+ lambda: int_quantity(quantity),
345
+ )
205
346
 
206
347
 
207
348
  def complex_quantity(quantity: Quantity) -> Quantity:
@@ -210,7 +351,119 @@ def complex_quantity(quantity: Quantity) -> Quantity:
210
351
  return Quantity(complex(quantity.value), quantity.unit)
211
352
 
212
353
 
213
- int_unit = int_quantity
214
- float_unit = float_quantity
215
- long_unit = long_quantity
216
- complex_unit = complex_quantity
354
+ def convert(quantity: Quantity, target_unit: BaseUnit) -> Quantity:
355
+ """
356
+ Convert a quantity to a compatible scale-only target unit.
357
+
358
+ Args:
359
+ quantity: Quantity to convert.
360
+ target_unit: Unit definition with the same dimension.
361
+
362
+ Returns:
363
+ Quantity expressed in ``target_unit``.
364
+
365
+ Raises:
366
+ UnitOperandError: If ``quantity`` is not a Quantity.
367
+ InvalidUnitError: If ``target_unit`` is not a unit definition.
368
+ UnitCompatibilityError: If conversion is not scale-only compatible.
369
+ """
370
+ require_quantity_operand(quantity, "conversion")
371
+ return quantity.to(target_unit)
372
+
373
+
374
+ def value(quantity: Quantity) -> Scalar:
375
+ """
376
+ Return the numeric value of a quantity without converting it.
377
+
378
+ Args:
379
+ quantity: Quantity to inspect.
380
+
381
+ Returns:
382
+ Numeric value stored on the quantity.
383
+
384
+ Raises:
385
+ UnitOperandError: If ``quantity`` is not a Quantity.
386
+ """
387
+ require_quantity_operand(quantity, "value extraction")
388
+ return quantity.value
389
+
390
+
391
+ def unit(quantity: Quantity) -> BaseUnit:
392
+ """
393
+ Return the unit definition of a quantity.
394
+
395
+ Args:
396
+ quantity: Quantity to inspect.
397
+
398
+ Returns:
399
+ Unit definition stored on the quantity.
400
+
401
+ Raises:
402
+ UnitOperandError: If ``quantity`` is not a Quantity.
403
+ """
404
+ require_quantity_operand(quantity, "unit extraction")
405
+ return quantity.unit
406
+
407
+
408
+ def multiplier(quantity_or_unit: Quantity | BaseUnit) -> float:
409
+ """
410
+ Return the multiplicative factor to the canonical base dimension.
411
+
412
+ Args:
413
+ quantity_or_unit: Quantity or unit definition to inspect.
414
+
415
+ Returns:
416
+ Multiplicative factor for the unit carried by the input.
417
+
418
+ Raises:
419
+ UnitOperandError: If the input is neither Quantity nor BaseUnit.
420
+ """
421
+ if isinstance(quantity_or_unit, Quantity):
422
+ return quantity_or_unit.unit.conversion_factor
423
+ if isinstance(quantity_or_unit, BaseUnit):
424
+ return quantity_or_unit.conversion_factor
425
+ raise UnitOperandError(
426
+ "unsupported operand for multiplier extraction: {}".format(
427
+ type(quantity_or_unit).__name__
428
+ )
429
+ )
430
+
431
+
432
+ def int_unit(quantity: Quantity) -> Quantity:
433
+ """Legacy compatibility helper equivalent to ``int_quantity``."""
434
+ return deprecated_call(
435
+ "int_unit",
436
+ "int_quantity",
437
+ "1.0.0",
438
+ lambda: int_quantity(quantity),
439
+ )
440
+
441
+
442
+ def float_unit(quantity: Quantity) -> Quantity:
443
+ """Legacy compatibility helper equivalent to ``float_quantity``."""
444
+ return deprecated_call(
445
+ "float_unit",
446
+ "float_quantity",
447
+ "1.0.0",
448
+ lambda: float_quantity(quantity),
449
+ )
450
+
451
+
452
+ def long_unit(quantity: Quantity) -> Quantity:
453
+ """Legacy compatibility helper equivalent to ``int_quantity``."""
454
+ return deprecated_call(
455
+ "long_unit",
456
+ "int_quantity",
457
+ "1.0.0",
458
+ lambda: int_quantity(quantity),
459
+ )
460
+
461
+
462
+ def complex_unit(quantity: Quantity) -> Quantity:
463
+ """Legacy compatibility helper equivalent to ``complex_quantity``."""
464
+ return deprecated_call(
465
+ "complex_unit",
466
+ "complex_quantity",
467
+ "1.0.0",
468
+ lambda: complex_quantity(quantity),
469
+ )