Move enum mapper to own file to prevent circular dependency (#90890)

* Move enum_mapper to own file to prevent circular dependency

* Add enum mapper test
This commit is contained in:
Jesse Hills 2023-04-06 14:55:51 +12:00 committed by GitHub
parent 2fc34e7cce
commit eb469d6a2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 93 additions and 67 deletions

View File

@ -5,12 +5,11 @@ from collections.abc import Callable
import functools import functools
import logging import logging
import math import math
from typing import Any, Generic, NamedTuple, TypeVar, cast, overload from typing import Any, Generic, NamedTuple, TypeVar, cast
from aioesphomeapi import ( from aioesphomeapi import (
APIClient, APIClient,
APIConnectionError, APIConnectionError,
APIIntEnum,
APIVersion, APIVersion,
DeviceInfo as EsphomeDeviceInfo, DeviceInfo as EsphomeDeviceInfo,
EntityCategory as EsphomeEntityCategory, EntityCategory as EsphomeEntityCategory,
@ -64,6 +63,7 @@ from .domain_data import DomainData
# Import config flow so that it's added to the registry # Import config flow so that it's added to the registry
from .entry_data import RuntimeEntryData from .entry_data import RuntimeEntryData
from .enum_mapper import EsphomeEnumMapper
CONF_DEVICE_NAME = "device_name" CONF_DEVICE_NAME = "device_name"
CONF_NOISE_PSK = "noise_psk" CONF_NOISE_PSK = "noise_psk"
@ -687,41 +687,6 @@ def esphome_state_property(
return _wrapper return _wrapper
_EnumT = TypeVar("_EnumT", bound=APIIntEnum)
_ValT = TypeVar("_ValT")
class EsphomeEnumMapper(Generic[_EnumT, _ValT]):
"""Helper class to convert between hass and esphome enum values."""
def __init__(self, mapping: dict[_EnumT, _ValT]) -> None:
"""Construct a EsphomeEnumMapper."""
# Add none mapping
augmented_mapping: dict[
_EnumT | None, _ValT | None
] = mapping # type: ignore[assignment]
augmented_mapping[None] = None
self._mapping = augmented_mapping
self._inverse: dict[_ValT, _EnumT] = {v: k for k, v in mapping.items()}
@overload
def from_esphome(self, value: _EnumT) -> _ValT:
...
@overload
def from_esphome(self, value: _EnumT | None) -> _ValT | None:
...
def from_esphome(self, value: _EnumT | None) -> _ValT | None:
"""Convert from an esphome int representation to a hass string."""
return self._mapping[value]
def from_hass(self, value: _ValT) -> _EnumT:
"""Convert from a hass string to a esphome int representation."""
return self._inverse[value]
ICON_SCHEMA = vol.Schema(cv.icon) ICON_SCHEMA = vol.Schema(cv.icon)

View File

@ -54,12 +54,8 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import ( from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry
EsphomeEntity, from .enum_mapper import EsphomeEnumMapper
EsphomeEnumMapper,
esphome_state_property,
platform_async_setup_entry,
)
FAN_QUIET = "quiet" FAN_QUIET = "quiet"

View File

@ -0,0 +1,39 @@
"""Helper class to convert between Home Assistant and ESPHome enum values."""
from typing import Generic, TypeVar, overload
from aioesphomeapi import APIIntEnum
_EnumT = TypeVar("_EnumT", bound=APIIntEnum)
_ValT = TypeVar("_ValT")
class EsphomeEnumMapper(Generic[_EnumT, _ValT]):
"""Helper class to convert between hass and esphome enum values."""
def __init__(self, mapping: dict[_EnumT, _ValT]) -> None:
"""Construct a EsphomeEnumMapper."""
# Add none mapping
augmented_mapping: dict[
_EnumT | None, _ValT | None
] = mapping # type: ignore[assignment]
augmented_mapping[None] = None
self._mapping = augmented_mapping
self._inverse: dict[_ValT, _EnumT] = {v: k for k, v in mapping.items()}
@overload
def from_esphome(self, value: _EnumT) -> _ValT:
...
@overload
def from_esphome(self, value: _EnumT | None) -> _ValT | None:
...
def from_esphome(self, value: _EnumT | None) -> _ValT | None:
"""Convert from an esphome int representation to a hass string."""
return self._mapping[value]
def from_hass(self, value: _ValT) -> _EnumT:
"""Convert from a hass string to a esphome int representation."""
return self._inverse[value]

View File

@ -22,12 +22,8 @@ from homeassistant.util.percentage import (
ranged_value_to_percentage, ranged_value_to_percentage,
) )
from . import ( from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry
EsphomeEntity, from .enum_mapper import EsphomeEnumMapper
EsphomeEnumMapper,
esphome_state_property,
platform_async_setup_entry,
)
ORDERED_NAMED_FAN_SPEEDS = [FanSpeed.LOW, FanSpeed.MEDIUM, FanSpeed.HIGH] ORDERED_NAMED_FAN_SPEEDS = [FanSpeed.LOW, FanSpeed.MEDIUM, FanSpeed.HIGH]

View File

@ -24,12 +24,8 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import ( from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry
EsphomeEntity, from .enum_mapper import EsphomeEnumMapper
EsphomeEnumMapper,
esphome_state_property,
platform_async_setup_entry,
)
async def async_setup_entry( async def async_setup_entry(

View File

@ -11,12 +11,8 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util.enum import try_parse_enum from homeassistant.util.enum import try_parse_enum
from . import ( from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry
EsphomeEntity, from .enum_mapper import EsphomeEnumMapper
EsphomeEnumMapper,
esphome_state_property,
platform_async_setup_entry,
)
async def async_setup_entry( async def async_setup_entry(

View File

@ -24,12 +24,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util import dt from homeassistant.util import dt
from homeassistant.util.enum import try_parse_enum from homeassistant.util.enum import try_parse_enum
from . import ( from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry
EsphomeEntity, from .enum_mapper import EsphomeEnumMapper
EsphomeEnumMapper,
esphome_state_property,
platform_async_setup_entry,
)
async def async_setup_entry( async def async_setup_entry(

View File

@ -0,0 +1,42 @@
"""Test ESPHome enum mapper."""
from aioesphomeapi import APIIntEnum
from homeassistant.backports.enum import StrEnum
from homeassistant.components.esphome.enum_mapper import EsphomeEnumMapper
class MockEnum(APIIntEnum):
"""Mock enum."""
ESPHOME_FOO = 1
ESPHOME_BAR = 2
class MockStrEnum(StrEnum):
"""Mock enum."""
HA_FOO = "foo"
HA_BAR = "bar"
MOCK_MAPPING: EsphomeEnumMapper[MockEnum, MockStrEnum] = EsphomeEnumMapper(
{
MockEnum.ESPHOME_FOO: MockStrEnum.HA_FOO,
MockEnum.ESPHOME_BAR: MockStrEnum.HA_BAR,
}
)
async def test_map_esphome_to_ha() -> None:
"""Test mapping from ESPHome to HA."""
assert MOCK_MAPPING.from_esphome(MockEnum.ESPHOME_FOO) == MockStrEnum.HA_FOO
assert MOCK_MAPPING.from_esphome(MockEnum.ESPHOME_BAR) == MockStrEnum.HA_BAR
async def test_map_ha_to_esphome() -> None:
"""Test mapping from HA to ESPHome."""
assert MOCK_MAPPING.from_hass(MockStrEnum.HA_FOO) == MockEnum.ESPHOME_FOO
assert MOCK_MAPPING.from_hass(MockStrEnum.HA_BAR) == MockEnum.ESPHOME_BAR