u 2.1__tar.gz → 3.1__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.
Files changed (58) hide show
  1. {u-2.1 → u-3.1}/PKG-INFO +2 -1
  2. u-3.1/changelog.md +20 -0
  3. {u-2.1 → u-3.1}/pyproject.toml +2 -0
  4. {u-2.1 → u-3.1}/tests/static_tests.py +10 -0
  5. {u-2.1 → u-3.1}/tests/test_conversions.py +3 -0
  6. u-3.1/tests/test_decimal.py +31 -0
  7. {u-2.1 → u-3.1}/tests/test_quantities.py +5 -0
  8. {u-2.1 → u-3.1}/tests/test_typing.py +11 -0
  9. {u-2.1 → u-3.1}/u/__init__.py +1 -1
  10. {u-2.1 → u-3.1}/u/_utils.py +3 -0
  11. u-3.1/u/maths.py +56 -0
  12. {u-2.1 → u-3.1}/u/prefixes.py +30 -27
  13. {u-2.1 → u-3.1}/u/quantities/__init__.py +4 -1
  14. {u-2.1 → u-3.1}/u/quantities/amount_of_substance.py +1 -1
  15. u-3.1/u/quantities/angle.py +38 -0
  16. u-3.1/u/quantities/area.py +29 -0
  17. u-3.1/u/quantities/distance.py +61 -0
  18. {u-2.1 → u-3.1}/u/quantities/duration.py +11 -10
  19. {u-2.1 → u-3.1}/u/quantities/electric_charge.py +2 -1
  20. {u-2.1 → u-3.1}/u/quantities/electric_current.py +1 -1
  21. {u-2.1 → u-3.1}/u/quantities/electric_resistance.py +2 -1
  22. u-3.1/u/quantities/energy.py +40 -0
  23. {u-2.1 → u-3.1}/u/quantities/force.py +1 -1
  24. {u-2.1 → u-3.1}/u/quantities/frequency.py +1 -1
  25. {u-2.1 → u-3.1}/u/quantities/luminous_intensity.py +1 -1
  26. {u-2.1 → u-3.1}/u/quantities/mass.py +15 -2
  27. u-3.1/u/quantities/power.py +32 -0
  28. u-3.1/u/quantities/pressure.py +35 -0
  29. u-3.1/u/quantities/speed.py +30 -0
  30. u-3.1/u/quantities/volume.py +51 -0
  31. {u-2.1 → u-3.1}/u/quantity.py +136 -56
  32. {u-2.1 → u-3.1}/u/unit.py +50 -12
  33. u-2.1/changelog.md +0 -8
  34. u-2.1/u/quantities/angle.py +0 -30
  35. u-2.1/u/quantities/area.py +0 -21
  36. u-2.1/u/quantities/distance.py +0 -44
  37. u-2.1/u/quantities/speed.py +0 -15
  38. {u-2.1 → u-3.1}/.gitignore +0 -0
  39. {u-2.1 → u-3.1}/LICENSE.txt +0 -0
  40. {u-2.1 → u-3.1}/README.md +0 -0
  41. {u-2.1 → u-3.1}/docs/api/quantity.md +0 -0
  42. {u-2.1 → u-3.1}/docs/api/unit.md +0 -0
  43. {u-2.1 → u-3.1}/docs/index.md +0 -0
  44. {u-2.1 → u-3.1}/mkdocs.yml +0 -0
  45. {u-2.1 → u-3.1}/tests/test_math.py +0 -0
  46. {u-2.1 → u-3.1}/tests/test_prefixes.py +0 -0
  47. {u-2.1 → u-3.1}/tests/test_units.py +0 -0
  48. {u-2.1 → u-3.1}/u/capital_quantities.py +0 -0
  49. {u-2.1 → u-3.1}/u/cli/__init__.py +0 -0
  50. {u-2.1 → u-3.1}/u/cli/make_derived_quantity.py +0 -0
  51. {u-2.1 → u-3.1}/u/quantities/acceleration.py +0 -0
  52. {u-2.1 → u-3.1}/u/quantities/data_transfer_speed.py +0 -0
  53. {u-2.1 → u-3.1}/u/quantities/data_volume.py +0 -0
  54. {u-2.1 → u-3.1}/u/quantities/one.py +0 -0
  55. {u-2.1 → u-3.1}/u/quantities/pixels.py +0 -0
  56. {u-2.1 → u-3.1}/u/quantities/solid_angle.py +0 -0
  57. {u-2.1 → u-3.1}/u/quantities/temperature.py +0 -0
  58. {u-2.1 → u-3.1}/uv.lock +0 -0
@@ -1,7 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: u
3
- Version: 2.1
3
+ Version: 3.1
4
4
  Summary: Statically typed units
5
+ Keywords: units,dimensions
5
6
  Author-email: Aran-Fey <rawing7@gmail.com>
6
7
  Requires-Python: >= 3.10
7
8
  Description-Content-Type: text/markdown
u-3.1/changelog.md ADDED
@@ -0,0 +1,20 @@
1
+ # 3.1
2
+
3
+ - Add `__hash__` method
4
+
5
+ # 3.0
6
+
7
+ - Add support for `decimal.Decimal`. Unlike floats and Decimals, which throw a TypeError when used
8
+ together, `Quantity`s remain interoperable regardless of whether they were created with a float or
9
+ a Decimal.
10
+ - `Unit.multiplier` is now a Decimal.
11
+ - Add `systems` parameter and attribute to `Unit`
12
+
13
+ # 2.1
14
+
15
+ - `Quantity.to_number` now raises `ValueError` if an incompatible unit is passed
16
+
17
+ # 2.0
18
+
19
+ - Removed `.unit` attribute of `Quantity` objects
20
+ - Renamed `ton` to `tonne`
@@ -3,10 +3,12 @@ name = "u"
3
3
  description = "Statically typed units"
4
4
  authors = [{ name = "Aran-Fey", email = "rawing7@gmail.com" }]
5
5
  license = "MIT"
6
+ license-files = ["LICENSE.txt"]
6
7
  readme = "README.md"
7
8
  dynamic = ["version"]
8
9
  requires-python = ">= 3.10"
9
10
  classifiers = ["Programming Language :: Python :: 3"]
11
+ keywords = ["units", "dimensions"]
10
12
 
11
13
  dependencies = ["typing-extensions"]
12
14
 
@@ -59,3 +59,13 @@ ZeroOrDuration = ZeroOrQuantity[u.DURATION]
59
59
 
60
60
  Speed = u.Quantity[u.DIV[Q, u.DURATION]]
61
61
  DownloadSpeed = Speed[u.DATA_VOLUME]
62
+
63
+
64
+ # Do the type guards work?
65
+ untyped_quantity: u.Quantity = u.Quantity(0)
66
+
67
+ if u.Distance.typecheck(untyped_quantity):
68
+ t.assert_type(untyped_quantity, u.Distance)
69
+
70
+ if u.seconds(3).is_compatible_with(untyped_quantity):
71
+ t.assert_type(untyped_quantity, u.Duration)
@@ -20,6 +20,7 @@ import u
20
20
  (u.meters_per_second(30), u.kilometers_per_hour, 108),
21
21
  (u.square_meters(1_000_000), u.square_kilometers, 1),
22
22
  ],
23
+ ids=lambda value: value.symbol if isinstance(value, u.Unit) else repr(value),
23
24
  )
24
25
  def test_to_number(value: u.Quantity, unit: u.Unit, expected_result: float):
25
26
  result = value.to_number(unit)
@@ -50,6 +51,8 @@ def test_repr(value: u.Quantity, expected_result: str):
50
51
  @pytest.mark.parametrize(
51
52
  "value, expected_result",
52
53
  [
54
+ (u.inches(63360), "1 mi"),
55
+ (u.centimeters(160934.4), "1.6 km"),
53
56
  (u.kilometers(0), "0 m"),
54
57
  (u.meters(7), "7 m"),
55
58
  (u.kilometers(3.5), ["3.5 km", "3500 m"]),
@@ -0,0 +1,31 @@
1
+ from decimal import Decimal
2
+
3
+ import u
4
+
5
+
6
+ def test_decimal_quantity():
7
+ dec = Decimal("10.5")
8
+ dist = u.meter(dec)
9
+
10
+ assert dist.to_decimal(u.meter) == dec
11
+
12
+
13
+ def test_decimal_math():
14
+ q1 = u.meter(Decimal("10.5"))
15
+ q2 = u.meter(Decimal("5.5"))
16
+ res = q1 + q2
17
+ assert res.to_decimal(u.meter) == Decimal("16.0")
18
+
19
+
20
+ def test_mixed_math():
21
+ q1 = u.meter(Decimal("10.5"))
22
+ q2 = u.meter(5.5)
23
+ res = q1 + q2
24
+ assert res.to_decimal(u.meter) == Decimal("16.0")
25
+
26
+
27
+ def test_decimal_conversion():
28
+ q = u.km(Decimal("1"))
29
+ res = q.to_decimal(u.meter)
30
+ assert res == Decimal("1000")
31
+ assert isinstance(res, Decimal)
@@ -8,3 +8,8 @@ def test_getitem():
8
8
 
9
9
  def test_equality():
10
10
  assert u.minutes(60) == u.hours(1)
11
+
12
+
13
+ def test_hashing():
14
+ mapping = {u.minutes(60): "foo"}
15
+ assert mapping[u.hours(1)] == "foo"
@@ -1,5 +1,6 @@
1
1
  import re
2
2
  import typing as t
3
+ import typing_extensions as te
3
4
  from pathlib import Path
4
5
 
5
6
  import mypy.api
@@ -34,6 +35,16 @@ def test_typevars_at_runtime():
34
35
  DownloadSpeed = Speed[u.DATA_VOLUME] # type: ignore
35
36
 
36
37
 
38
+ def test_typecheck():
39
+ assert u.Distance.typecheck(u.meters(3))
40
+ assert not u.Distance.typecheck(u.seconds(3))
41
+
42
+
43
+ def test_is_compatible_with():
44
+ assert u.meters(3).is_compatible_with(u.km(3))
45
+ assert not u.meters(3).is_compatible_with(u.seconds(3))
46
+
47
+
37
48
  @pytest.mark.parametrize(
38
49
  "expr",
39
50
  [
@@ -1,4 +1,4 @@
1
- __version__ = "2.1"
1
+ __version__ = "3.1"
2
2
 
3
3
  from .prefixes import *
4
4
  from .quantity import *
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import collections.abc
4
+ import decimal
4
5
  import functools
5
6
  import re
6
7
  import sys
@@ -9,6 +10,8 @@ import typing as t
9
10
 
10
11
  import u
11
12
 
13
+ from .maths import FloatOrDecimal
14
+
12
15
 
13
16
  C = t.TypeVar("C", bound=t.Callable)
14
17
 
u-3.1/u/maths.py ADDED
@@ -0,0 +1,56 @@
1
+ """
2
+ Floats and Decimals refuse to cooperate, so any math involving mixed types will throw an error. This
3
+ module can be used to safely perform math without worrying about the types of the operands.
4
+ """
5
+
6
+ import decimal
7
+ import operator
8
+ import typing as t
9
+
10
+
11
+ FloatOrDecimal = float | decimal.Decimal
12
+ TypePreference = type[float] | type[decimal.Decimal] | None
13
+
14
+
15
+ def add(
16
+ lhs: FloatOrDecimal, rhs: FloatOrDecimal, type_preference: TypePreference = None
17
+ ) -> FloatOrDecimal:
18
+ return apply_operator(operator.add, lhs, rhs, type_preference)
19
+
20
+
21
+ def subtract(
22
+ lhs: FloatOrDecimal, rhs: FloatOrDecimal, type_preference: TypePreference = None
23
+ ) -> FloatOrDecimal:
24
+ return apply_operator(operator.sub, lhs, rhs, type_preference)
25
+
26
+
27
+ def multiply(
28
+ lhs: FloatOrDecimal, rhs: FloatOrDecimal, type_preference: TypePreference = None
29
+ ) -> FloatOrDecimal:
30
+ return apply_operator(operator.mul, lhs, rhs, type_preference)
31
+
32
+
33
+ def divide(
34
+ lhs: FloatOrDecimal, rhs: FloatOrDecimal, type_preference: TypePreference = None
35
+ ) -> FloatOrDecimal:
36
+ return apply_operator(operator.truediv, lhs, rhs, type_preference)
37
+
38
+
39
+ def apply_operator(
40
+ operator: t.Callable[[float, float], float],
41
+ lhs: FloatOrDecimal,
42
+ rhs: FloatOrDecimal,
43
+ type_preference: TypePreference = None,
44
+ ) -> FloatOrDecimal:
45
+ try:
46
+ return operator(lhs, rhs) # type: ignore
47
+ except TypeError:
48
+ pass
49
+
50
+ if type_preference is None:
51
+ type_preference = type(lhs)
52
+
53
+ lhs = type_preference(lhs)
54
+ rhs = type_preference(rhs)
55
+
56
+ return operator(lhs, rhs) # type: ignore
@@ -1,9 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import decimal
3
4
  import typing as t
4
5
 
5
6
  import u
6
7
 
8
+ from .maths import multiply
7
9
  from ._utils import cached
8
10
 
9
11
  __all__ = [
@@ -48,9 +50,9 @@ max_prefix_length = 0
48
50
 
49
51
 
50
52
  class Prefix:
51
- def __init__(self, symbol: str, multiplier: float):
53
+ def __init__(self, symbol: str, multiplier: decimal.Decimal | int):
52
54
  self.symbol = symbol
53
- self.multiplier = multiplier
55
+ self.multiplier = decimal.Decimal(multiplier)
54
56
 
55
57
  prefix_by_symbol[symbol] = self
56
58
 
@@ -72,7 +74,8 @@ class Prefix:
72
74
  return u.unit.lookup_unit(
73
75
  unit.quantity,
74
76
  self.symbol + unit.symbol,
75
- self.multiplier * unit.multiplier,
77
+ multiply(self.multiplier, unit.multiplier, decimal.Decimal),
78
+ unit.systems,
76
79
  )
77
80
 
78
81
  def __repr__(self) -> str:
@@ -82,30 +85,30 @@ class Prefix:
82
85
  DUMMY_PREFIX = Prefix("", 1)
83
86
 
84
87
 
85
- quecto = Prefix("q", 1e-30)
86
- ronto = Prefix("r", 1e-27)
87
- yocto = Prefix("y", 1e-24)
88
- zepto = Prefix("z", 1e-21)
89
- atto = Prefix("a", 1e-18)
90
- femto = Prefix("f", 1e-15)
91
- pico = Prefix("p", 1e-12)
92
- nano = Prefix("n", 1e-9)
93
- micro = Prefix("µ", 1e-6)
94
- milli = Prefix("m", 1e-3)
95
- centi = Prefix("c", 1e-2)
96
- deci = Prefix("d", 1e-1)
97
- deka = Prefix("da", 1e1)
98
- hecto = Prefix("h", 1e2)
99
- kilo = Prefix("k", 1e3)
100
- mega = Prefix("M", 1e6)
101
- giga = Prefix("G", 1e9)
102
- tera = Prefix("T", 1e12)
103
- peta = Prefix("P", 1e15)
104
- exa = Prefix("E", 1e18)
105
- zetta = Prefix("Z", 1e21)
106
- yotta = Prefix("Y", 1e24)
107
- ronna = Prefix("R", 1e27)
108
- quetta = Prefix("Q", 1e30)
88
+ quecto = Prefix("q", decimal.Decimal("1e-30"))
89
+ ronto = Prefix("r", decimal.Decimal("1e-27"))
90
+ yocto = Prefix("y", decimal.Decimal("1e-24"))
91
+ zepto = Prefix("z", decimal.Decimal("1e-21"))
92
+ atto = Prefix("a", decimal.Decimal("1e-18"))
93
+ femto = Prefix("f", decimal.Decimal("1e-15"))
94
+ pico = Prefix("p", decimal.Decimal("1e-12"))
95
+ nano = Prefix("n", decimal.Decimal("1e-9"))
96
+ micro = Prefix("µ", decimal.Decimal("1e-6"))
97
+ milli = Prefix("m", decimal.Decimal("1e-3"))
98
+ centi = Prefix("c", decimal.Decimal("1e-2"))
99
+ deci = Prefix("d", decimal.Decimal("1e-1"))
100
+ deka = Prefix("da", 10**1)
101
+ hecto = Prefix("h", 10**2)
102
+ kilo = Prefix("k", 10**3)
103
+ mega = Prefix("M", 10**6)
104
+ giga = Prefix("G", 10**9)
105
+ tera = Prefix("T", 10**12)
106
+ peta = Prefix("P", 10**15)
107
+ exa = Prefix("E", 10**18)
108
+ zetta = Prefix("Z", 10**21)
109
+ yotta = Prefix("Y", 10**24)
110
+ ronna = Prefix("R", 10**27)
111
+ quetta = Prefix("Q", 10**30)
109
112
 
110
113
 
111
114
  STANDARD_SI_PREFIXES = (
@@ -8,13 +8,16 @@ from .duration import *
8
8
  from .electric_charge import *
9
9
  from .electric_current import *
10
10
  from .electric_resistance import *
11
- from .data_volume import *
11
+ from .energy import *
12
12
  from .force import *
13
13
  from .frequency import *
14
14
  from .luminous_intensity import *
15
15
  from .mass import *
16
16
  from .one import *
17
17
  from .pixels import *
18
+ from .power import *
19
+ from .pressure import *
18
20
  from .solid_angle import *
19
21
  from .speed import *
20
22
  from .temperature import *
23
+ from .volume import *
@@ -19,4 +19,4 @@ class AMOUNT_OF_SUBSTANCE(QUANTITY):
19
19
  AmountOfSubstance = Quantity[AMOUNT_OF_SUBSTANCE]
20
20
 
21
21
 
22
- moles = mole = mol = Unit(AmountOfSubstance, "mol", 1)
22
+ moles = mole = mol = Unit(AmountOfSubstance, "mol", 1, systems={"metric"})
@@ -0,0 +1,38 @@
1
+ import decimal
2
+
3
+ from ..quantity import Quantity
4
+ from ..capital_quantities import QUANTITY
5
+ from ..unit import Unit
6
+
7
+
8
+ # fmt: off
9
+ __all__ = [
10
+ "ANGLE",
11
+ "Angle",
12
+ "radians", "radian", "rad",
13
+ "degrees", "degree", "deg",
14
+ "gradians", "gradian", "gons", "gon",
15
+ "turns", "turn", "tr",
16
+ "arcminutes", "arcminute", "arcmin",
17
+ "arcseconds", "arcsecond", "arcsec",
18
+ ]
19
+ # fmt: on
20
+
21
+
22
+ # Standard PI with high precision for Decimal math
23
+ PI = decimal.Decimal("3.1415926535897932384626433832795028841971")
24
+
25
+
26
+ class ANGLE(QUANTITY):
27
+ pass
28
+
29
+
30
+ Angle = Quantity[ANGLE]
31
+
32
+
33
+ radians = radian = rad = Unit(Angle, "rad", 1)
34
+ degrees = degree = deg = Unit(Angle, "°", 2 * PI / 360)
35
+ gradians = gradian = gons = gon = Unit(Angle, "ᵍ", 2 * PI / 400)
36
+ turns = turn = tr = Unit(Angle, "tr", 2 * PI)
37
+ arcminutes = arcminute = arcmin = Unit(Angle, "′", PI / 10800)
38
+ arcseconds = arcsecond = arcsec = Unit(Angle, "″", PI / 648000)
@@ -0,0 +1,29 @@
1
+ import decimal
2
+
3
+ from .distance import DISTANCE, meter, kilometer
4
+ from ..quantity import Quantity
5
+ from ..capital_quantities import MUL
6
+ from ..unit import Unit
7
+
8
+
9
+ # fmt: off
10
+ __all__ = [
11
+ "AREA",
12
+ "Area",
13
+ "square_meters", "square_meter", "m2",
14
+ "square_kilometers", "square_kilometer", "km2",
15
+ "hectares", "hectare", "ha",
16
+ "acres", "acre",
17
+ ]
18
+ # fmt: on
19
+
20
+
21
+ AREA = MUL[DISTANCE, DISTANCE]
22
+
23
+ Area = Quantity[AREA]
24
+
25
+
26
+ square_meters = square_meter = m2 = Unit(meter**2, "m²", systems={"metric"})
27
+ square_kilometers = square_kilometer = km2 = Unit(kilometer**2, "km²", systems={"metric"})
28
+ hectares = hectare = ha = Unit(Area, "ha", 10_000, systems={"metric"})
29
+ acres = acre = Unit(Area, "acre", decimal.Decimal("4046.8564224"), systems={"imperial"})
@@ -0,0 +1,61 @@
1
+ import decimal
2
+
3
+ from ..prefixes import nano, micro, milli, centi, deci, kilo
4
+ from ..quantity import Quantity
5
+ from ..capital_quantities import QUANTITY
6
+ from ..unit import Unit
7
+
8
+
9
+ # fmt: off
10
+ __all__ = [
11
+ "DISTANCE",
12
+ "Distance",
13
+ "nanometers", "nanometer", "nm",
14
+ "micrometers", "micrometer", "μm",
15
+ "millimeters", "millimeter", "mm",
16
+ "centimeters", "centimeter", "cm",
17
+ "decimeters", "decimeter", "dm",
18
+ "meters", "meter", "m",
19
+ "kilometers", "kilometer", "km",
20
+ "light_seconds", "light_second", "ls",
21
+ "light_years", "light_year", "ly",
22
+ "astronomical_units", "astronomical_unit", "au",
23
+ "parsecs", "parsec", "pc",
24
+ "inches", "inch", "in_",
25
+ "feet", "foot", "ft",
26
+ "yards", "yard", "yd",
27
+ "miles", "mile", "mi",
28
+ "nautical_miles", "nautical_mile", "nmi",
29
+ "fathoms", "fathom",
30
+ "mils", "mil",
31
+ ]
32
+ # fmt: on
33
+
34
+
35
+ class DISTANCE(QUANTITY):
36
+ pass
37
+
38
+
39
+ Distance = Quantity[DISTANCE]
40
+
41
+
42
+ meters = meter = m = Unit(Distance, "m", 1, systems={"metric"})
43
+ light_seconds = light_second = ls = Unit(Distance, "ls", 299792458)
44
+ light_years = light_year = ly = Unit(Distance, "ly", 9460730472580800)
45
+ astronomical_units = astronomical_unit = au = Unit(Distance, "au", 149597870700)
46
+ parsecs = parsec = pc = Unit(Distance, "pc", decimal.Decimal("3.0856775814913673e16"))
47
+
48
+ inches = inch = in_ = Unit(Distance, "in", decimal.Decimal("0.0254"), systems={"imperial"})
49
+ feet = foot = ft = Unit(Distance, "ft", decimal.Decimal("0.3048"), systems={"imperial"})
50
+ yards = yard = yd = Unit(Distance, "yd", decimal.Decimal("0.9144"), systems={"imperial"})
51
+ miles = mile = mi = Unit(Distance, "mi", decimal.Decimal("1609.344"), systems={"imperial"})
52
+ nautical_miles = nautical_mile = nmi = Unit(Distance, "nmi", 1852, systems={"nautical"})
53
+ fathoms = fathom = Unit(Distance, "fathom", decimal.Decimal("1.8288"), systems={"nautical"})
54
+ mils = mil = Unit(Distance, "mil", decimal.Decimal("0.0000254"), systems={"imperial"})
55
+
56
+ nanometers = nanometer = nm = nano(meter)
57
+ micrometers = micrometer = μm = micro(meter)
58
+ millimeters = millimeter = mm = milli(meter)
59
+ centimeters = centimeter = cm = centi(meter)
60
+ decimeters = decimeter = dm = deci(meter)
61
+ kilometers = kilometer = km = kilo(meter)
@@ -28,13 +28,14 @@ class DURATION(QUANTITY):
28
28
  Duration = Quantity[DURATION]
29
29
  Duration.prefixes = SI_PREFIXES[: SI_PREFIXES.index(milli) + 1]
30
30
 
31
-
32
- seconds = second = sec = s = Unit(Duration, "s", 1)
33
- minutes = minute = min = Unit(Duration, "min", 60)
34
- hours = hour = h = Unit(Duration, "h", 3_600)
35
- days = day = d = Unit(Duration, "d", 86_400)
36
- weeks = week = wk = w = Unit(Duration, "wk", 604_800)
37
- years = year = yr = y = Unit(Duration, "yr", 31_536_000)
38
- decades = decade = dec = Unit(Duration, "dec", 315_360_000)
39
- centuries = century = cent = c = Unit(Duration, "cent", 3_153_600_000)
40
- millenia = millenium = mil = ka = ky = Unit(Duration, "mil", 31_536_000_000)
31
+ SYSTEMS = {"metric", "imperial", "nautical"}
32
+
33
+ seconds = second = sec = s = Unit(Duration, "s", 1, systems=SYSTEMS)
34
+ minutes = minute = min = Unit(Duration, "min", 60, systems=SYSTEMS)
35
+ hours = hour = h = Unit(Duration, "h", 3_600, systems=SYSTEMS)
36
+ days = day = d = Unit(Duration, "d", 86_400, systems=SYSTEMS)
37
+ weeks = week = wk = w = Unit(Duration, "wk", 604_800, systems=SYSTEMS)
38
+ years = year = yr = y = Unit(Duration, "yr", 31_536_000, systems=SYSTEMS)
39
+ decades = decade = dec = Unit(Duration, "dec", 315_360_000, systems=SYSTEMS)
40
+ centuries = century = cent = c = Unit(Duration, "cent", 3_153_600_000, systems=SYSTEMS)
41
+ millenia = millenium = mil = ka = ky = Unit(Duration, "mil", 31_536_000_000, systems=SYSTEMS)
@@ -17,4 +17,5 @@ ELECTRIC_CHARGE = MUL[DURATION, ELECTRIC_CURRENT]
17
17
 
18
18
  ElectricCharge = Quantity[ELECTRIC_CHARGE]
19
19
 
20
- coulombs = coulomb = C = Unit(seconds * amperes, "C")
20
+
21
+ coulombs = coulomb = C = Unit(seconds * amperes, "C", systems={"metric"})
@@ -19,4 +19,4 @@ class ELECTRIC_CURRENT(QUANTITY):
19
19
  ElectricCurrent = Quantity[ELECTRIC_CURRENT]
20
20
 
21
21
 
22
- amperes = ampere = A = Unit(ElectricCurrent, "A", 1)
22
+ amperes = ampere = A = Unit(ElectricCurrent, "A", 1, systems={"metric"})
@@ -23,4 +23,5 @@ ELECTRIC_RESISTANCE = t.Union[
23
23
 
24
24
  ElectricResistance = Quantity[ELECTRIC_RESISTANCE]
25
25
 
26
- ohms = ohm = Unit(kg * m**2 / s**3 / A**2, "Ω")
26
+
27
+ ohms = ohm = Unit(kg * m**2 / s**3 / A**2, "Ω", systems={"metric"})
@@ -0,0 +1,40 @@
1
+ import decimal
2
+
3
+ from .force import FORCE, newtons
4
+ from .distance import DISTANCE, meters
5
+ from ..quantity import Quantity
6
+ from ..capital_quantities import MUL
7
+ from ..unit import Unit
8
+
9
+
10
+ # fmt: off
11
+ __all__ = [
12
+ "ENERGY",
13
+ "Energy",
14
+ "joules", "joule", "J",
15
+ "calories", "calorie", "cal",
16
+ "kilocalories", "kilocalorie", "kcal",
17
+ "kilowatt_hours", "kilowatt_hour", "kWh",
18
+ "electronvolts", "electronvolt", "eV",
19
+ "ergs", "erg",
20
+ "btus", "btu", "BTU",
21
+ ]
22
+ # fmt: on
23
+
24
+
25
+ ENERGY = MUL[FORCE, DISTANCE]
26
+
27
+ Energy = Quantity[ENERGY]
28
+
29
+
30
+ joules = joule = J = Unit(newtons * meters, "J", systems={"metric"})
31
+ calories = calorie = cal = Unit(Energy, "cal", decimal.Decimal("4.184") * joule.multiplier)
32
+ kilocalories = kilocalorie = kcal = Unit(Energy, "kcal", 4184 * joule.multiplier)
33
+ kilowatt_hours = kilowatt_hour = kWh = Unit(Energy, "kWh", 3600000 * joule.multiplier)
34
+ electronvolts = electronvolt = eV = Unit(
35
+ Energy, "eV", decimal.Decimal("1.602176634e-19") * joule.multiplier, systems={"technical"}
36
+ )
37
+ ergs = erg = Unit(Energy, "erg", decimal.Decimal("1e-7") * joule.multiplier, systems={"metric"})
38
+ btus = btu = BTU = Unit(
39
+ Energy, "BTU", decimal.Decimal("1055.05585262") * joule.multiplier, systems={"imperial"}
40
+ )
@@ -30,4 +30,4 @@ FORCE = t.Union[
30
30
  Force = Quantity[FORCE]
31
31
 
32
32
 
33
- newtons = newton = N = Unit(kg * m / s / s, "N")
33
+ newtons = newton = N = Unit(kg * m / s / s, "N", systems={"metric"})
@@ -24,7 +24,7 @@ FREQUENCY = DIV[ONE, DURATION]
24
24
  Frequency = Quantity[FREQUENCY]
25
25
 
26
26
 
27
- hertzes = hertz = Hz = Unit(one / seconds, "Hz")
27
+ hertzes = hertz = Hz = Unit(one / seconds, "Hz", systems={"metric"})
28
28
 
29
29
  kilohertzes = kilohertz = KHz = kilo(hertz)
30
30
  megahertzes = megahertz = MHz = mega(hertz)
@@ -13,4 +13,4 @@ class LUMINOUS_INTENSITY(QUANTITY):
13
13
  LuminousIntensity = Quantity[LUMINOUS_INTENSITY]
14
14
 
15
15
 
16
- candelas = candela = cd = Unit(LuminousIntensity, "cd", 1)
16
+ candelas = candela = cd = Unit(LuminousIntensity, "cd", 1, systems={"metric"})
@@ -1,3 +1,5 @@
1
+ import decimal
2
+
1
3
  from ..prefixes import nano, micro, milli, centi, deci, kilo, mega
2
4
  from ..quantity import Quantity
3
5
  from ..capital_quantities import QUANTITY
@@ -18,6 +20,11 @@ __all__ = [
18
20
  "metric_tons", "metric_ton", "tonnes", "tonne", "t",
19
21
  "kilotonnes", "kilotonne", "kt",
20
22
  "megatonnes", "megatonne", "Mt",
23
+ "pounds", "pound", "lb",
24
+ "ounces", "ounce", "oz",
25
+ "stones", "stone", "st",
26
+ "slugs", "slug",
27
+ "daltons", "dalton", "Da",
21
28
  ]
22
29
  # fmt: on
23
30
 
@@ -29,10 +36,16 @@ class MASS(QUANTITY):
29
36
  Mass = Quantity[MASS]
30
37
 
31
38
 
32
- grams = gram = g = Unit(Mass, "g", 1)
39
+ grams = gram = g = Unit(Mass, "g", 1, systems={"metric"})
33
40
 
34
41
  # Careful: "ton" is not the same thing as "tonne".
35
- metric_tons = metric_ton = tonnes = tonne = t = Unit(Mass, "t", 1_000_000)
42
+ metric_tons = metric_ton = tonnes = tonne = t = Unit(Mass, "t", 1000000, systems={"metric"})
43
+
44
+ pounds = pound = lb = Unit(Mass, "lb", decimal.Decimal("453.59237"), systems={"imperial"})
45
+ ounces = ounce = oz = Unit(Mass, "oz", decimal.Decimal("28.349523125"), systems={"imperial"})
46
+ stones = stone = st = Unit(Mass, "st", decimal.Decimal("6350.29318"), systems={"imperial"})
47
+ slugs = slug = Unit(Mass, "slug", decimal.Decimal("14593.9029"), systems={"imperial"})
48
+ daltons = dalton = Da = Unit(Mass, "Da", decimal.Decimal("1.66053906660e-24"))
36
49
 
37
50
  nanograms = nanogram = ng = nano(grams)
38
51
  micrograms = microgram = μg = micro(grams)
@@ -0,0 +1,32 @@
1
+ import decimal
2
+
3
+ from .energy import ENERGY, joules
4
+ from .duration import DURATION, seconds
5
+ from ..quantity import Quantity
6
+ from ..capital_quantities import DIV
7
+ from ..unit import Unit
8
+
9
+
10
+ # fmt: off
11
+ __all__ = [
12
+ "POWER",
13
+ "Power",
14
+ "watts", "watt", "W",
15
+ "kilowatts", "kilowatt", "kW",
16
+ "megawatts", "megawatt", "MW",
17
+ "horsepower", "hp",
18
+ ]
19
+ # fmt: on
20
+
21
+
22
+ POWER = DIV[ENERGY, DURATION]
23
+
24
+ Power = Quantity[POWER]
25
+
26
+
27
+ watts = watt = W = Unit(joules / seconds, "W", systems={"metric"})
28
+ kilowatts = kilowatt = kW = Unit(Power, "kW", 1000 * watt.multiplier, systems={"metric"})
29
+ megawatts = megawatt = MW = Unit(Power, "MW", 1000000 * watt.multiplier, systems={"metric"})
30
+ horsepower = hp = Unit(
31
+ Power, "hp", decimal.Decimal("745.69987158227") * watt.multiplier, systems={"imperial"}
32
+ )