diff --git a/homeassistant/util/unit_conversion.py b/homeassistant/util/unit_conversion.py index 344aef9028ad4752ad34f9c922280162cb8f3b53..45feb08361123b91aa5786dfcf822a448dc176ae 100644 --- a/homeassistant/util/unit_conversion.py +++ b/homeassistant/util/unit_conversion.py @@ -2,7 +2,6 @@ from __future__ import annotations from abc import abstractmethod -from numbers import Number from homeassistant.const import ( ENERGY_KILO_WATT_HOUR, @@ -46,6 +45,7 @@ from homeassistant.const import ( VOLUME_LITERS, VOLUME_MILLILITERS, ) +from homeassistant.exceptions import HomeAssistantError # Distance conversion constants _MM_TO_M = 0.001 # 1 mm = 0.001 m @@ -78,21 +78,6 @@ class BaseUnitConverter: NORMALIZED_UNIT: str VALID_UNITS: set[str] - @classmethod - def _check_arguments(cls, value: float, from_unit: str, to_unit: str) -> None: - """Check that arguments are all valid.""" - if from_unit not in cls.VALID_UNITS: - raise ValueError( - UNIT_NOT_RECOGNIZED_TEMPLATE.format(from_unit, cls.UNIT_CLASS) - ) - if to_unit not in cls.VALID_UNITS: - raise ValueError( - UNIT_NOT_RECOGNIZED_TEMPLATE.format(to_unit, cls.UNIT_CLASS) - ) - - if not isinstance(value, Number): - raise TypeError(f"{value} is not of numeric type") - @classmethod @abstractmethod def convert(cls, value: float, from_unit: str, to_unit: str) -> float: @@ -107,13 +92,25 @@ class BaseUnitConverterWithUnitConversion(BaseUnitConverter): @classmethod def convert(cls, value: float, from_unit: str, to_unit: str) -> float: """Convert one unit of measurement to another.""" - cls._check_arguments(value, from_unit, to_unit) - if from_unit == to_unit: return value - new_value = value / cls.UNIT_CONVERSION[from_unit] - return new_value * cls.UNIT_CONVERSION[to_unit] + try: + from_ratio = cls.UNIT_CONVERSION[from_unit] + except KeyError as err: + raise HomeAssistantError( + UNIT_NOT_RECOGNIZED_TEMPLATE.format(from_unit, cls.UNIT_CLASS) + ) from err + + try: + to_ratio = cls.UNIT_CONVERSION[to_unit] + except KeyError as err: + raise HomeAssistantError( + UNIT_NOT_RECOGNIZED_TEMPLATE.format(to_unit, cls.UNIT_CLASS) + ) from err + + new_value = value / from_ratio + return new_value * to_ratio class DistanceConverter(BaseUnitConverterWithUnitConversion): @@ -247,31 +244,41 @@ class TemperatureConverter(BaseUnitConverter): cls, value: float, from_unit: str, to_unit: str, *, interval: bool = False ) -> float: """Convert a temperature from one unit to another.""" - cls._check_arguments(value, from_unit, to_unit) - if from_unit == to_unit: return value if from_unit == TEMP_CELSIUS: if to_unit == TEMP_FAHRENHEIT: return cls.celsius_to_fahrenheit(value, interval) - # kelvin - return cls.celsius_to_kelvin(value, interval) + if to_unit == TEMP_KELVIN: + return cls.celsius_to_kelvin(value, interval) + raise HomeAssistantError( + UNIT_NOT_RECOGNIZED_TEMPLATE.format(to_unit, cls.UNIT_CLASS) + ) if from_unit == TEMP_FAHRENHEIT: if to_unit == TEMP_CELSIUS: return cls.fahrenheit_to_celsius(value, interval) - # kelvin - return cls.celsius_to_kelvin( - cls.fahrenheit_to_celsius(value, interval), interval + if to_unit == TEMP_KELVIN: + return cls.celsius_to_kelvin( + cls.fahrenheit_to_celsius(value, interval), interval + ) + raise HomeAssistantError( + UNIT_NOT_RECOGNIZED_TEMPLATE.format(to_unit, cls.UNIT_CLASS) ) - # from_unit == kelvin - if to_unit == TEMP_CELSIUS: - return cls.kelvin_to_celsius(value, interval) - # fahrenheit - return cls.celsius_to_fahrenheit( - cls.kelvin_to_celsius(value, interval), interval + if from_unit == TEMP_KELVIN: + if to_unit == TEMP_CELSIUS: + return cls.kelvin_to_celsius(value, interval) + if to_unit == TEMP_FAHRENHEIT: + return cls.celsius_to_fahrenheit( + cls.kelvin_to_celsius(value, interval), interval + ) + raise HomeAssistantError( + UNIT_NOT_RECOGNIZED_TEMPLATE.format(to_unit, cls.UNIT_CLASS) + ) + raise HomeAssistantError( + UNIT_NOT_RECOGNIZED_TEMPLATE.format(from_unit, cls.UNIT_CLASS) ) @classmethod diff --git a/tests/util/test_distance.py b/tests/util/test_distance.py index eb001add114b8e78f96eca6b1d8760d5a2073ac0..652f95d7bf0e09503a7343d5b6d268bef56cfac0 100644 --- a/tests/util/test_distance.py +++ b/tests/util/test_distance.py @@ -12,6 +12,7 @@ from homeassistant.const import ( LENGTH_MILLIMETERS, LENGTH_YARD, ) +from homeassistant.exceptions import HomeAssistantError import homeassistant.util.distance as distance_util INVALID_SYMBOL = "bob" @@ -32,10 +33,10 @@ def test_convert_same_unit(): def test_convert_invalid_unit(): """Test exception is thrown for invalid units.""" - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): distance_util.convert(5, INVALID_SYMBOL, VALID_SYMBOL) - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): distance_util.convert(5, VALID_SYMBOL, INVALID_SYMBOL) diff --git a/tests/util/test_pressure.py b/tests/util/test_pressure.py index e3b6ed92e4dbccdd45e20d1678cae701c275806b..13c1a6d1225c2828a509e19e9d2109c47f266a8f 100644 --- a/tests/util/test_pressure.py +++ b/tests/util/test_pressure.py @@ -11,6 +11,7 @@ from homeassistant.const import ( PRESSURE_PA, PRESSURE_PSI, ) +from homeassistant.exceptions import HomeAssistantError import homeassistant.util.pressure as pressure_util INVALID_SYMBOL = "bob" @@ -30,10 +31,10 @@ def test_convert_same_unit(): def test_convert_invalid_unit(): """Test exception is thrown for invalid units.""" - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): pressure_util.convert(5, INVALID_SYMBOL, VALID_SYMBOL) - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): pressure_util.convert(5, VALID_SYMBOL, INVALID_SYMBOL) diff --git a/tests/util/test_speed.py b/tests/util/test_speed.py index 9c7fd0703134fac118b9a7c0e3ce2d22fa8c3796..f944f0a5d8c61b4e235fb84b4badce0dba52347a 100644 --- a/tests/util/test_speed.py +++ b/tests/util/test_speed.py @@ -11,6 +11,7 @@ from homeassistant.const import ( SPEED_MILES_PER_HOUR, SPEED_MILLIMETERS_PER_DAY, ) +from homeassistant.exceptions import HomeAssistantError import homeassistant.util.speed as speed_util INVALID_SYMBOL = "bob" @@ -33,10 +34,10 @@ def test_convert_same_unit(): def test_convert_invalid_unit(): """Test exception is thrown for invalid units.""" - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): speed_util.convert(5, INVALID_SYMBOL, VALID_SYMBOL) - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): speed_util.convert(5, VALID_SYMBOL, INVALID_SYMBOL) diff --git a/tests/util/test_temperature.py b/tests/util/test_temperature.py index 71693683fa35e0eaae9036c706d611c6b527de21..7151d6ed816328b5c7199898582f65e7891d35ba 100644 --- a/tests/util/test_temperature.py +++ b/tests/util/test_temperature.py @@ -2,6 +2,7 @@ import pytest from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT, TEMP_KELVIN +from homeassistant.exceptions import HomeAssistantError import homeassistant.util.temperature as temperature_util INVALID_SYMBOL = "bob" @@ -34,10 +35,10 @@ def test_convert_same_unit(): def test_convert_invalid_unit(): """Test exception is thrown for invalid units.""" - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): temperature_util.convert(5, INVALID_SYMBOL, VALID_SYMBOL) - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): temperature_util.convert(5, VALID_SYMBOL, INVALID_SYMBOL) diff --git a/tests/util/test_unit_conversion.py b/tests/util/test_unit_conversion.py index fb31624d255333b79a62e0da103d93b607eddecb..a1835c87f85581343f96063f405a388ec6fc7d1d 100644 --- a/tests/util/test_unit_conversion.py +++ b/tests/util/test_unit_conversion.py @@ -41,6 +41,7 @@ from homeassistant.const import ( VOLUME_LITERS, VOLUME_MILLILITERS, ) +from homeassistant.exceptions import HomeAssistantError from homeassistant.util.unit_conversion import ( BaseUnitConverter, DistanceConverter, @@ -110,6 +111,8 @@ def test_convert_same_unit(converter: type[BaseUnitConverter], valid_unit: str) (PressureConverter, PRESSURE_PA), (SpeedConverter, SPEED_KILOMETERS_PER_HOUR), (TemperatureConverter, TEMP_CELSIUS), + (TemperatureConverter, TEMP_FAHRENHEIT), + (TemperatureConverter, TEMP_KELVIN), (VolumeConverter, VOLUME_LITERS), ], ) @@ -117,10 +120,10 @@ def test_convert_invalid_unit( converter: type[BaseUnitConverter], valid_unit: str ) -> None: """Test exception is thrown for invalid units.""" - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): converter.convert(5, INVALID_SYMBOL, valid_unit) - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): converter.convert(5, valid_unit, INVALID_SYMBOL) diff --git a/tests/util/test_unit_system.py b/tests/util/test_unit_system.py index c4cc94636b18cb883070fb1b8031c5d7eedf4774..a284fd100178b5f7a1584289a70d55a66cfd81ee 100644 --- a/tests/util/test_unit_system.py +++ b/tests/util/test_unit_system.py @@ -18,6 +18,7 @@ from homeassistant.const import ( VOLUME_LITERS, WIND_SPEED, ) +from homeassistant.exceptions import HomeAssistantError from homeassistant.util.unit_system import IMPERIAL_SYSTEM, METRIC_SYSTEM, UnitSystem SYSTEM_NAME = "TEST" @@ -149,7 +150,7 @@ def test_temperature_same_unit(): def test_temperature_unknown_unit(): """Test no conversion happens if unknown unit.""" - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): METRIC_SYSTEM.temperature(5, "abc") @@ -170,7 +171,7 @@ def test_temperature_to_imperial(): def test_length_unknown_unit(): """Test length conversion with unknown from unit.""" - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): METRIC_SYSTEM.length(5, "fr") @@ -192,7 +193,7 @@ def test_length_to_imperial(): def test_wind_speed_unknown_unit(): """Test wind_speed conversion with unknown from unit.""" - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): METRIC_SYSTEM.length(5, "turtles") @@ -220,7 +221,7 @@ def test_pressure_same_unit(): def test_pressure_unknown_unit(): """Test no conversion happens if unknown unit.""" - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): METRIC_SYSTEM.pressure(5, "K") @@ -252,7 +253,7 @@ def test_accumulated_precipitation_same_unit(): def test_accumulated_precipitation_unknown_unit(): """Test no conversion happens if unknown unit.""" - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): METRIC_SYSTEM.accumulated_precipitation(5, "K") diff --git a/tests/util/test_volume.py b/tests/util/test_volume.py index 5362f3099fb3a6508d2773d35507a52e6360cca0..c556a3b073d897dbf87d3f60ba38f124f0821cfd 100644 --- a/tests/util/test_volume.py +++ b/tests/util/test_volume.py @@ -10,6 +10,7 @@ from homeassistant.const import ( VOLUME_LITERS, VOLUME_MILLILITERS, ) +from homeassistant.exceptions import HomeAssistantError import homeassistant.util.volume as volume_util INVALID_SYMBOL = "bob" @@ -43,10 +44,10 @@ def test_convert_same_unit(): def test_convert_invalid_unit(): """Test exception is thrown for invalid units.""" - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): volume_util.convert(5, INVALID_SYMBOL, VALID_SYMBOL) - with pytest.raises(ValueError): + with pytest.raises(HomeAssistantError, match="is not a recognized .* unit"): volume_util.convert(5, VALID_SYMBOL, INVALID_SYMBOL)