Skip to content

Commit 7ac01de

Browse files
committed
Disable default constructor for specialized Quantity types
Specialized quantities can only be instantiated through custom constructors after this. Signed-off-by: Sahas Subramanian <[email protected]>
1 parent 3a259d5 commit 7ac01de

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

src/frequenz/sdk/timeseries/_quantities.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import math
99
from datetime import timedelta
10-
from typing import Self, TypeVar, overload
10+
from typing import Any, NoReturn, Self, TypeVar, overload
1111

1212
QuantityT = TypeVar("QuantityT", "Quantity", "Power", "Current", "Voltage", "Energy")
1313

@@ -279,8 +279,29 @@ def __eq__(self, other: object) -> bool:
279279
return self._base_value == other._base_value
280280

281281

282+
class _NoDefaultConstructible(type):
283+
"""A metaclass that disables the default constructor."""
284+
285+
def __call__(cls, *_args: Any, **_kwargs: Any) -> NoReturn:
286+
"""Raise a TypeError when the default constructor is called.
287+
288+
Args:
289+
_args: ignored positional arguments.
290+
_kwargs: ignored keyword arguments.
291+
292+
Raises:
293+
TypeError: Always.
294+
"""
295+
raise TypeError(
296+
"Use of default constructor NOT allowed for "
297+
f"{cls.__module__}.{cls.__qualname__}, "
298+
f"use one of the `{cls.__name__}.from_*()` methods instead."
299+
)
300+
301+
282302
class Power(
283303
Quantity,
304+
metaclass=_NoDefaultConstructible,
284305
exponent_unit_map={
285306
-3: "mW",
286307
0: "W",
@@ -422,6 +443,7 @@ def __truediv__(self, other: Current | Voltage) -> Voltage | Current:
422443

423444
class Current(
424445
Quantity,
446+
metaclass=_NoDefaultConstructible,
425447
exponent_unit_map={
426448
-3: "mA",
427449
0: "A",
@@ -485,7 +507,11 @@ def __mul__(self, voltage: Voltage) -> Power:
485507
return Power.from_watts(self._base_value * voltage._base_value)
486508

487509

488-
class Voltage(Quantity, exponent_unit_map={0: "V", -3: "mV", 3: "kV"}):
510+
class Voltage(
511+
Quantity,
512+
metaclass=_NoDefaultConstructible,
513+
exponent_unit_map={0: "V", -3: "mV", 3: "kV"},
514+
):
489515
"""A voltage quantity."""
490516

491517
@classmethod
@@ -568,6 +594,7 @@ def __mul__(self, current: Current) -> Power:
568594

569595
class Energy(
570596
Quantity,
597+
metaclass=_NoDefaultConstructible,
571598
exponent_unit_map={
572599
0: "Wh",
573600
3: "kWh",

tests/timeseries/test_quantities.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ def test_power() -> None:
177177
assert power == Power.from_megawatts(0.0012)
178178
assert power != Power.from_watts(1000.0)
179179

180+
with pytest.raises(TypeError):
181+
# using the default constructor should raise.
182+
Power(1.0, exponent=0)
183+
180184

181185
def test_current() -> None:
182186
"""Test the current class."""
@@ -192,6 +196,10 @@ def test_current() -> None:
192196
assert current == Current.from_amperes(6.0)
193197
assert current != Current.from_amperes(5.0)
194198

199+
with pytest.raises(TypeError):
200+
# using the default constructor should raise.
201+
Current(1.0, exponent=0)
202+
195203

196204
def test_voltage() -> None:
197205
"""Test the voltage class."""
@@ -209,6 +217,10 @@ def test_voltage() -> None:
209217
assert voltage == Voltage.from_volts(6.0)
210218
assert voltage != Voltage.from_volts(5.0)
211219

220+
with pytest.raises(TypeError):
221+
# using the default constructor should raise.
222+
Voltage(1.0, exponent=0)
223+
212224

213225
def test_energy() -> None:
214226
"""Test the energy class."""
@@ -225,6 +237,10 @@ def test_energy() -> None:
225237
assert energy == Energy.from_kilowatt_hours(6.0)
226238
assert energy != Energy.from_kilowatt_hours(5.0)
227239

240+
with pytest.raises(TypeError):
241+
# using the default constructor should raise.
242+
Energy(1.0, exponent=0)
243+
228244

229245
def test_quantity_compositions() -> None:
230246
"""Test the composition of quantities."""

0 commit comments

Comments
 (0)