From ecf00a1eaec3dcbd5667650408042567047e173b Mon Sep 17 00:00:00 2001 From: rianadon Date: Fri, 19 Nov 2021 00:18:44 -0800 Subject: [PATCH] Add accumulated precipitation to unit system (#59657) * Add accumulated precipitation to unit system * Fix template test * Fix typo of testing pressure instead of precipitation * Add extra arguments so unit system test passes --- homeassistant/const.py | 1 + homeassistant/util/unit_system.py | 21 ++++++++++ tests/helpers/test_template.py | 2 + tests/util/test_unit_system.py | 66 +++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+) diff --git a/homeassistant/const.py b/homeassistant/const.py index da48646beed..dd8bbc5e555 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -688,6 +688,7 @@ TEMPERATURE: Final = "temperature" SPEED: Final = "speed" WIND_SPEED: Final = "wind_speed" ILLUMINANCE: Final = "illuminance" +ACCUMULATED_PRECIPITATION: Final = "accumulated_precipitation" WEEKDAYS: Final[list[str]] = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"] diff --git a/homeassistant/util/unit_system.py b/homeassistant/util/unit_system.py index 1956faea84d..bdb637a9149 100644 --- a/homeassistant/util/unit_system.py +++ b/homeassistant/util/unit_system.py @@ -4,11 +4,14 @@ from __future__ import annotations from numbers import Number from homeassistant.const import ( + ACCUMULATED_PRECIPITATION, CONF_UNIT_SYSTEM_IMPERIAL, CONF_UNIT_SYSTEM_METRIC, LENGTH, + LENGTH_INCHES, LENGTH_KILOMETERS, LENGTH_MILES, + LENGTH_MILLIMETERS, MASS, MASS_GRAMS, MASS_KILOGRAMS, @@ -55,6 +58,8 @@ def is_valid_unit(unit: str, unit_type: str) -> bool: """Check if the unit is valid for it's type.""" if unit_type == LENGTH: units = LENGTH_UNITS + elif unit_type == ACCUMULATED_PRECIPITATION: + units = LENGTH_UNITS elif unit_type == WIND_SPEED: units = WIND_SPEED_UNITS elif unit_type == TEMPERATURE: @@ -83,11 +88,13 @@ class UnitSystem: volume: str, mass: str, pressure: str, + accumulated_precipitation: str, ) -> None: """Initialize the unit system object.""" errors: str = ", ".join( UNIT_NOT_RECOGNIZED_TEMPLATE.format(unit, unit_type) for unit, unit_type in ( + (accumulated_precipitation, ACCUMULATED_PRECIPITATION), (temperature, TEMPERATURE), (length, LENGTH), (wind_speed, WIND_SPEED), @@ -102,6 +109,7 @@ class UnitSystem: raise ValueError(errors) self.name = name + self.accumulated_precipitation_unit = accumulated_precipitation self.temperature_unit = temperature self.length_unit = length self.mass_unit = mass @@ -131,6 +139,16 @@ class UnitSystem: length, from_unit, self.length_unit ) + def accumulated_precipitation(self, precip: float | None, from_unit: str) -> float: + """Convert the given length to this unit system.""" + if not isinstance(precip, Number): + raise TypeError(f"{precip!s} is not a numeric value.") + + # type ignore: https://github.com/python/mypy/issues/7207 + return distance_util.convert( # type: ignore + precip, from_unit, self.accumulated_precipitation_unit + ) + def pressure(self, pressure: float | None, from_unit: str) -> float: """Convert the given pressure to this unit system.""" if not isinstance(pressure, Number): @@ -161,6 +179,7 @@ class UnitSystem: """Convert the unit system to a dictionary.""" return { LENGTH: self.length_unit, + ACCUMULATED_PRECIPITATION: self.accumulated_precipitation_unit, MASS: self.mass_unit, PRESSURE: self.pressure_unit, TEMPERATURE: self.temperature_unit, @@ -177,6 +196,7 @@ METRIC_SYSTEM = UnitSystem( VOLUME_LITERS, MASS_GRAMS, PRESSURE_PA, + LENGTH_MILLIMETERS, ) IMPERIAL_SYSTEM = UnitSystem( @@ -187,4 +207,5 @@ IMPERIAL_SYSTEM = UnitSystem( VOLUME_GALLONS, MASS_POUNDS, PRESSURE_PSI, + LENGTH_INCHES, ) diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index f871fc88d3a..0e1d96b8dac 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -12,6 +12,7 @@ from homeassistant.config import async_process_ha_core_config from homeassistant.const import ( ATTR_UNIT_OF_MEASUREMENT, LENGTH_METERS, + LENGTH_MILLIMETERS, MASS_GRAMS, PRESSURE_PA, SPEED_KILOMETERS_PER_HOUR, @@ -42,6 +43,7 @@ def _set_up_units(hass): VOLUME_LITERS, MASS_GRAMS, PRESSURE_PA, + LENGTH_MILLIMETERS, ) diff --git a/tests/util/test_unit_system.py b/tests/util/test_unit_system.py index 5c7ac660f9b..954df07fc9d 100644 --- a/tests/util/test_unit_system.py +++ b/tests/util/test_unit_system.py @@ -2,9 +2,11 @@ import pytest from homeassistant.const import ( + ACCUMULATED_PRECIPITATION, LENGTH, LENGTH_KILOMETERS, LENGTH_METERS, + LENGTH_MILLIMETERS, MASS, MASS_GRAMS, PRESSURE, @@ -33,6 +35,7 @@ def test_invalid_units(): VOLUME_LITERS, MASS_GRAMS, PRESSURE_PA, + LENGTH_MILLIMETERS, ) with pytest.raises(ValueError): @@ -44,6 +47,7 @@ def test_invalid_units(): VOLUME_LITERS, MASS_GRAMS, PRESSURE_PA, + LENGTH_MILLIMETERS, ) with pytest.raises(ValueError): @@ -55,6 +59,7 @@ def test_invalid_units(): VOLUME_LITERS, MASS_GRAMS, PRESSURE_PA, + LENGTH_MILLIMETERS, ) with pytest.raises(ValueError): @@ -66,6 +71,7 @@ def test_invalid_units(): INVALID_UNIT, MASS_GRAMS, PRESSURE_PA, + LENGTH_MILLIMETERS, ) with pytest.raises(ValueError): @@ -77,6 +83,7 @@ def test_invalid_units(): VOLUME_LITERS, INVALID_UNIT, PRESSURE_PA, + LENGTH_MILLIMETERS, ) with pytest.raises(ValueError): @@ -88,6 +95,19 @@ def test_invalid_units(): VOLUME_LITERS, MASS_GRAMS, INVALID_UNIT, + LENGTH_MILLIMETERS, + ) + + with pytest.raises(ValueError): + UnitSystem( + SYSTEM_NAME, + TEMP_CELSIUS, + LENGTH_METERS, + SPEED_METERS_PER_SECOND, + VOLUME_LITERS, + MASS_GRAMS, + PRESSURE_PA, + INVALID_UNIT, ) @@ -103,6 +123,8 @@ def test_invalid_value(): METRIC_SYSTEM.volume("50L", VOLUME_LITERS) with pytest.raises(TypeError): METRIC_SYSTEM.pressure("50Pa", PRESSURE_PA) + with pytest.raises(TypeError): + METRIC_SYSTEM.accumulated_precipitation("50mm", LENGTH_MILLIMETERS) def test_as_dict(): @@ -114,6 +136,7 @@ def test_as_dict(): VOLUME: VOLUME_LITERS, MASS: MASS_GRAMS, PRESSURE: PRESSURE_PA, + ACCUMULATED_PRECIPITATION: LENGTH_MILLIMETERS, } assert expected == METRIC_SYSTEM.as_dict() @@ -213,6 +236,48 @@ def test_pressure_to_imperial(): ) == pytest.approx(14.7, abs=1e-4) +def test_accumulated_precipitation_same_unit(): + """Test no conversion happens if to unit is same as from unit.""" + assert ( + METRIC_SYSTEM.accumulated_precipitation( + 5, METRIC_SYSTEM.accumulated_precipitation_unit + ) + == 5 + ) + + +def test_accumulated_precipitation_unknown_unit(): + """Test no conversion happens if unknown unit.""" + with pytest.raises(ValueError): + METRIC_SYSTEM.accumulated_precipitation(5, "K") + + +def test_accumulated_precipitation_to_metric(): + """Test accumulated_precipitation conversion to metric system.""" + assert ( + METRIC_SYSTEM.accumulated_precipitation( + 25, METRIC_SYSTEM.accumulated_precipitation_unit + ) + == 25 + ) + assert METRIC_SYSTEM.accumulated_precipitation( + 10, IMPERIAL_SYSTEM.accumulated_precipitation_unit + ) == pytest.approx(254, abs=1e-4) + + +def test_accumulated_precipitation_to_imperial(): + """Test accumulated_precipitation conversion to imperial system.""" + assert ( + IMPERIAL_SYSTEM.accumulated_precipitation( + 10, IMPERIAL_SYSTEM.accumulated_precipitation_unit + ) + == 10 + ) + assert IMPERIAL_SYSTEM.accumulated_precipitation( + 254, METRIC_SYSTEM.accumulated_precipitation_unit + ) == pytest.approx(10, abs=1e-4) + + def test_properties(): """Test the unit properties are returned as expected.""" assert METRIC_SYSTEM.length_unit == LENGTH_KILOMETERS @@ -221,6 +286,7 @@ def test_properties(): assert METRIC_SYSTEM.mass_unit == MASS_GRAMS assert METRIC_SYSTEM.volume_unit == VOLUME_LITERS assert METRIC_SYSTEM.pressure_unit == PRESSURE_PA + assert METRIC_SYSTEM.accumulated_precipitation_unit == LENGTH_MILLIMETERS def test_is_metric():