diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 19cc6e9..c3fbeea 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -3,3 +3,7 @@ ## Summary This is the initial release, extracted from the [SDK v1.0.0rc601](https://github.com/frequenz-floss/frequenz-sdk-python/releases/tag/v1.0.0-rc601). + +## New Features + +- Added support for `__round__` (`round(quantity)`), `__pos__` (`+quantity`) and `__mod__` (`quantity % quantity`) operators. diff --git a/src/frequenz/quantities/_quantity.py b/src/frequenz/quantities/_quantity.py index 4b32996..4f55b91 100644 --- a/src/frequenz/quantities/_quantity.py +++ b/src/frequenz/quantities/_quantity.py @@ -139,6 +139,36 @@ def base_value(self) -> float: """ return self._base_value + def __round__(self, ndigits: int | None = None) -> Self: + """Round this quantity to the given number of digits. + + Args: + ndigits: The number of digits to round to. + + Returns: + The rounded quantity. + """ + return self._new(round(self._base_value, ndigits)) + + def __pos__(self) -> Self: + """Return this quantity. + + Returns: + This quantity. + """ + return self + + def __mod__(self, other: Self) -> Self: + """Return the remainder of this quantity and another. + + Args: + other: The other quantity. + + Returns: + The remainder of this quantity and another. + """ + return self._new(self._base_value % other._base_value) + @property def base_unit(self) -> str | None: """Return the base unit of this quantity. diff --git a/tests/test_quantities.py b/tests/test_quantities.py index 7b69897..ce9ffdb 100644 --- a/tests/test_quantities.py +++ b/tests/test_quantities.py @@ -234,6 +234,24 @@ def test_isclose() -> None: assert not Fz1(1.024445).isclose(Fz1(1.0)) +@hypothesis.given(value=st.floats(allow_nan=False, allow_infinity=False)) +@pytest.mark.parametrize("ndigits", [0, 1, 2, 3]) +def test_round(value: float, ndigits: int) -> None: + """Test the rounding of the quantities.""" + assert round(Quantity(value), ndigits) == Quantity(round(value, ndigits)) + + +@hypothesis.given( + dividend=st.floats(allow_infinity=False, allow_nan=False), + divisor=st.floats( + allow_nan=False, allow_infinity=False, min_value=0.0, exclude_min=True + ), +) +def test_mod(dividend: float, divisor: float) -> None: + """Test the modulo operation of the quantities.""" + assert Quantity(dividend) % Quantity(divisor) == Quantity(dividend % divisor) + + def test_addition_subtraction() -> None: """Test the addition and subtraction of the quantities.""" assert Quantity(1) + Quantity(1, exponent=0) == Quantity(2, exponent=0) @@ -486,6 +504,33 @@ def test_neg() -> None: assert -(-pct) == pct +def test_pos() -> None: + """Test the positive sign of quantities.""" + power = Power.from_watts(1000.0) + assert +power == power + assert +(+power) == power + + voltage = Voltage.from_volts(230.0) + assert +voltage == voltage + assert +(+voltage) == voltage + + current = Current.from_amperes(2) + assert +current == current + assert +(+current) == current + + energy = Energy.from_kilowatt_hours(6.2) + assert +energy == energy + assert +(+energy) == energy + + freq = Frequency.from_hertz(50) + assert +freq == freq + assert +(+freq) == freq + + pct = Percentage.from_fraction(30) + assert +pct == pct + assert +(+pct) == pct + + def test_inf() -> None: """Test proper formating when using inf in quantities.""" assert f"{Power.from_watts(float('inf'))}" == "inf W"