frequenz-quantities 1.0.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.
@@ -0,0 +1,235 @@
1
+ # License: MIT
2
+ # Copyright © 2024 Frequenz Energy-as-a-Service GmbH
3
+
4
+ """Types for holding reactive power quantities with units."""
5
+
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING, Self, overload
10
+
11
+ from ._quantity import NoDefaultConstructible, Quantity
12
+
13
+ if TYPE_CHECKING:
14
+ from ._current import Current
15
+ from ._percentage import Percentage
16
+ from ._voltage import Voltage
17
+
18
+
19
+ class ReactivePower(
20
+ Quantity,
21
+ metaclass=NoDefaultConstructible,
22
+ exponent_unit_map={
23
+ -3: "mVAR",
24
+ 0: "VAR",
25
+ 3: "kVAR",
26
+ 6: "MVAR",
27
+ },
28
+ ):
29
+ """A reactive power quantity.
30
+
31
+ Objects of this type are wrappers around `float` values and are immutable.
32
+
33
+ The constructors accept a single `float` value, the `as_*()` methods return a
34
+ `float` value, and each of the arithmetic operators supported by this type are
35
+ actually implemented using floating-point arithmetic.
36
+
37
+ So all considerations about floating-point arithmetic apply to this type as well.
38
+ """
39
+
40
+ @classmethod
41
+ def from_volt_amperes_reactive(cls, value: float) -> Self:
42
+ """Initialize a new reactive power quantity.
43
+
44
+ Args:
45
+ value: The reactive power in volt-amperes reactive (VAR).
46
+
47
+ Returns:
48
+ A new reactive power quantity.
49
+ """
50
+ return cls._new(value)
51
+
52
+ @classmethod
53
+ def from_milli_volt_amperes_reactive(cls, mvars: float) -> Self:
54
+ """Initialize a new reactive power quantity.
55
+
56
+ Args:
57
+ mvars: The reactive power in millivolt-amperes reactive (mVAR).
58
+
59
+ Returns:
60
+ A new reactive power quantity.
61
+ """
62
+ return cls._new(mvars, exponent=-3)
63
+
64
+ @classmethod
65
+ def from_kilo_volt_amperes_reactive(cls, kvars: float) -> Self:
66
+ """Initialize a new reactive power quantity.
67
+
68
+ Args:
69
+ kvars: The reactive power in kilovolt-amperes reactive (kVAR).
70
+
71
+ Returns:
72
+ A new reactive power quantity.
73
+ """
74
+ return cls._new(kvars, exponent=3)
75
+
76
+ @classmethod
77
+ def from_mega_volt_amperes_reactive(cls, mvars: float) -> Self:
78
+ """Initialize a new reactive power quantity.
79
+
80
+ Args:
81
+ mvars: The reactive power in megavolt-amperes reactive (MVAR).
82
+
83
+ Returns:
84
+ A new reactive power quantity.
85
+ """
86
+ return cls._new(mvars, exponent=6)
87
+
88
+ def as_volt_amperes_reactive(self) -> float:
89
+ """Return the reactive power in volt-amperes reactive (VAR).
90
+
91
+ Returns:
92
+ The reactive power in volt-amperes reactive (VAR).
93
+ """
94
+ return self._base_value
95
+
96
+ def as_milli_volt_amperes_reactive(self) -> float:
97
+ """Return the reactive power in millivolt-amperes reactive (mVAR).
98
+
99
+ Returns:
100
+ The reactive power in millivolt-amperes reactive (mVAR).
101
+ """
102
+ return self._base_value * 1e3
103
+
104
+ def as_kilo_volt_amperes_reactive(self) -> float:
105
+ """Return the reactive power in kilovolt-amperes reactive (kVAR).
106
+
107
+ Returns:
108
+ The reactive power in kilovolt-amperes reactive (kVAR).
109
+ """
110
+ return self._base_value / 1e3
111
+
112
+ def as_mega_volt_amperes_reactive(self) -> float:
113
+ """Return the reactive power in megavolt-amperes reactive (MVAR).
114
+
115
+ Returns:
116
+ The reactive power in megavolt-amperes reactive (MVAR).
117
+ """
118
+ return self._base_value / 1e6
119
+
120
+ @overload
121
+ def __mul__(self, scalar: float, /) -> Self:
122
+ """Scale this power by a scalar.
123
+
124
+ Args:
125
+ scalar: The scalar by which to scale this power.
126
+
127
+ Returns:
128
+ The scaled power.
129
+ """
130
+
131
+ @overload
132
+ def __mul__(self, percent: Percentage, /) -> Self:
133
+ """Scale this power by a percentage.
134
+
135
+ Args:
136
+ percent: The percentage by which to scale this power.
137
+
138
+ Returns:
139
+ The scaled power.
140
+ """
141
+
142
+ def __mul__(self, other: float | Percentage, /) -> Self:
143
+ """Return a power or energy from multiplying this power by the given value.
144
+
145
+ Args:
146
+ other: The scalar, percentage or duration to multiply by.
147
+
148
+ Returns:
149
+ A power or energy.
150
+ """
151
+ from ._percentage import Percentage # pylint: disable=import-outside-toplevel
152
+
153
+ match other:
154
+ case float() | Percentage():
155
+ return super().__mul__(other)
156
+ case _:
157
+ return NotImplemented
158
+
159
+ # We need the ignore here because otherwise mypy will give this error:
160
+ # > Overloaded operator methods can't have wider argument types in overrides
161
+ # The problem seems to be when the other type implements an **incompatible**
162
+ # __rmul__ method, which is not the case here, so we should be safe.
163
+ # Please see this example:
164
+ # https://github.com/python/mypy/blob/c26f1297d4f19d2d1124a30efc97caebb8c28616/test-data/unit/check-overloading.test#L4738C1-L4769C55
165
+ # And a discussion in a mypy issue here:
166
+ # https://github.com/python/mypy/issues/4985#issuecomment-389692396
167
+ @overload # type: ignore[override]
168
+ def __truediv__(self, other: float, /) -> Self:
169
+ """Divide this power by a scalar.
170
+
171
+ Args:
172
+ other: The scalar to divide this power by.
173
+
174
+ Returns:
175
+ The divided power.
176
+ """
177
+
178
+ @overload
179
+ def __truediv__(self, other: Self, /) -> float:
180
+ """Return the ratio of this power to another.
181
+
182
+ Args:
183
+ other: The other power.
184
+
185
+ Returns:
186
+ The ratio of this power to another.
187
+ """
188
+
189
+ @overload
190
+ def __truediv__(self, current: Current, /) -> Voltage:
191
+ """Return a voltage from dividing this power by the given current.
192
+
193
+ Args:
194
+ current: The current to divide by.
195
+
196
+ Returns:
197
+ A voltage from dividing this power by the a current.
198
+ """
199
+
200
+ @overload
201
+ def __truediv__(self, voltage: Voltage, /) -> Current:
202
+ """Return a current from dividing this power by the given voltage.
203
+
204
+ Args:
205
+ voltage: The voltage to divide by.
206
+
207
+ Returns:
208
+ A current from dividing this power by a voltage.
209
+ """
210
+
211
+ def __truediv__(
212
+ self, other: float | Self | Current | Voltage, /
213
+ ) -> Self | float | Voltage | Current:
214
+ """Return a current or voltage from dividing this power by the given value.
215
+
216
+ Args:
217
+ other: The scalar, power, current or voltage to divide by.
218
+
219
+ Returns:
220
+ A current or voltage from dividing this power by the given value.
221
+ """
222
+ from ._current import Current # pylint: disable=import-outside-toplevel
223
+ from ._voltage import Voltage # pylint: disable=import-outside-toplevel
224
+
225
+ match other:
226
+ case float():
227
+ return super().__truediv__(other)
228
+ case ReactivePower():
229
+ return self._base_value / other._base_value
230
+ case Current():
231
+ return Voltage._new(self._base_value / other._base_value)
232
+ case Voltage():
233
+ return Current._new(self._base_value / other._base_value)
234
+ case _:
235
+ return NotImplemented
@@ -0,0 +1,39 @@
1
+ # License: MIT
2
+ # Copyright © 2022 Frequenz Energy-as-a-Service GmbH
3
+
4
+ """Types for holding quantities with units."""
5
+
6
+
7
+ from typing import Self
8
+
9
+ from ._quantity import NoDefaultConstructible, Quantity
10
+
11
+
12
+ class Temperature(
13
+ Quantity,
14
+ metaclass=NoDefaultConstructible,
15
+ exponent_unit_map={
16
+ 0: "°C",
17
+ },
18
+ ):
19
+ """A temperature quantity (in degrees Celsius)."""
20
+
21
+ @classmethod
22
+ def from_celsius(cls, value: float) -> Self:
23
+ """Initialize a new temperature quantity.
24
+
25
+ Args:
26
+ value: The temperature in degrees Celsius.
27
+
28
+ Returns:
29
+ A new temperature quantity.
30
+ """
31
+ return cls._new(value)
32
+
33
+ def as_celsius(self) -> float:
34
+ """Return the temperature in degrees Celsius.
35
+
36
+ Returns:
37
+ The temperature in degrees Celsius.
38
+ """
39
+ return self._base_value
@@ -0,0 +1,148 @@
1
+ # License: MIT
2
+ # Copyright © 2022 Frequenz Energy-as-a-Service GmbH
3
+
4
+ """Types for holding quantities with units."""
5
+
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING, Self, overload
10
+
11
+ from ._quantity import NoDefaultConstructible, Quantity
12
+
13
+ if TYPE_CHECKING:
14
+ from ._current import Current
15
+ from ._percentage import Percentage
16
+ from ._power import Power
17
+
18
+
19
+ class Voltage(
20
+ Quantity,
21
+ metaclass=NoDefaultConstructible,
22
+ exponent_unit_map={0: "V", -3: "mV", 3: "kV"},
23
+ ):
24
+ """A voltage quantity.
25
+
26
+ Objects of this type are wrappers around `float` values and are immutable.
27
+
28
+ The constructors accept a single `float` value, the `as_*()` methods return a
29
+ `float` value, and each of the arithmetic operators supported by this type are
30
+ actually implemented using floating-point arithmetic.
31
+
32
+ So all considerations about floating-point arithmetic apply to this type as well.
33
+ """
34
+
35
+ @classmethod
36
+ def from_volts(cls, volts: float) -> Self:
37
+ """Initialize a new voltage quantity.
38
+
39
+ Args:
40
+ volts: The voltage in volts.
41
+
42
+ Returns:
43
+ A new voltage quantity.
44
+ """
45
+ return cls._new(volts)
46
+
47
+ @classmethod
48
+ def from_millivolts(cls, millivolts: float) -> Self:
49
+ """Initialize a new voltage quantity.
50
+
51
+ Args:
52
+ millivolts: The voltage in millivolts.
53
+
54
+ Returns:
55
+ A new voltage quantity.
56
+ """
57
+ return cls._new(millivolts, exponent=-3)
58
+
59
+ @classmethod
60
+ def from_kilovolts(cls, kilovolts: float) -> Self:
61
+ """Initialize a new voltage quantity.
62
+
63
+ Args:
64
+ kilovolts: The voltage in kilovolts.
65
+
66
+ Returns:
67
+ A new voltage quantity.
68
+ """
69
+ return cls._new(kilovolts, exponent=3)
70
+
71
+ def as_volts(self) -> float:
72
+ """Return the voltage in volts.
73
+
74
+ Returns:
75
+ The voltage in volts.
76
+ """
77
+ return self._base_value
78
+
79
+ def as_millivolts(self) -> float:
80
+ """Return the voltage in millivolts.
81
+
82
+ Returns:
83
+ The voltage in millivolts.
84
+ """
85
+ return self._base_value * 1e3
86
+
87
+ def as_kilovolts(self) -> float:
88
+ """Return the voltage in kilovolts.
89
+
90
+ Returns:
91
+ The voltage in kilovolts.
92
+ """
93
+ return self._base_value / 1e3
94
+
95
+ # See comment for Power.__mul__ for why we need the ignore here.
96
+ @overload # type: ignore[override]
97
+ def __mul__(self, scalar: float, /) -> Self:
98
+ """Scale this voltage by a scalar.
99
+
100
+ Args:
101
+ scalar: The scalar by which to scale this voltage.
102
+
103
+ Returns:
104
+ The scaled voltage.
105
+ """
106
+
107
+ @overload
108
+ def __mul__(self, percent: Percentage, /) -> Self:
109
+ """Scale this voltage by a percentage.
110
+
111
+ Args:
112
+ percent: The percentage by which to scale this voltage.
113
+
114
+ Returns:
115
+ The scaled voltage.
116
+ """
117
+
118
+ @overload
119
+ def __mul__(self, other: Current, /) -> Power:
120
+ """Multiply the voltage by the current to get the power.
121
+
122
+ Args:
123
+ other: The current to multiply the voltage with.
124
+
125
+ Returns:
126
+ The calculated power.
127
+ """
128
+
129
+ def __mul__(self, other: float | Percentage | Current, /) -> Self | Power:
130
+ """Return a voltage or power from multiplying this voltage by the given value.
131
+
132
+ Args:
133
+ other: The scalar, percentage or current to multiply by.
134
+
135
+ Returns:
136
+ The calculated voltage or power.
137
+ """
138
+ from ._current import Current # pylint: disable=import-outside-toplevel
139
+ from ._percentage import Percentage # pylint: disable=import-outside-toplevel
140
+ from ._power import Power # pylint: disable=import-outside-toplevel
141
+
142
+ match other:
143
+ case float() | Percentage():
144
+ return super().__mul__(other)
145
+ case Current():
146
+ return Power._new(self._base_value * other._base_value)
147
+ case _:
148
+ return NotImplemented
@@ -0,0 +1,13 @@
1
+ # License: MIT
2
+ # Copyright © 2024 Frequenz Energy-as-a-Service GmbH
3
+
4
+ """Validate docstring code examples.
5
+
6
+ Code examples are often wrapped in triple backticks (```) within docstrings.
7
+ This plugin extracts these code examples and validates them using pylint.
8
+ """
9
+
10
+ from frequenz.repo.config.pytest import examples
11
+ from sybil import Sybil
12
+
13
+ pytest_collect_file = Sybil(**examples.get_sybil_arguments()).pytest()
@@ -0,0 +1,11 @@
1
+ # License: All rights reserved
2
+ # Copyright © 2024 Frequenz Energy-as-a-Service GmbH
3
+
4
+ """Experimental features for quantities.
5
+
6
+ Danger:
7
+ This package contains experimental features for which the API is not yet stable.
8
+
9
+ Any module or class in this package may be removed or changed in a future release,
10
+ even in minor or patch releases.
11
+ """