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:
parent
2fc34e7cce
commit
eb469d6a2f
8 changed files with 93 additions and 67 deletions
|
@ -5,12 +5,11 @@ from collections.abc import Callable
|
|||
import functools
|
||||
import logging
|
||||
import math
|
||||
from typing import Any, Generic, NamedTuple, TypeVar, cast, overload
|
||||
from typing import Any, Generic, NamedTuple, TypeVar, cast
|
||||
|
||||
from aioesphomeapi import (
|
||||
APIClient,
|
||||
APIConnectionError,
|
||||
APIIntEnum,
|
||||
APIVersion,
|
||||
DeviceInfo as EsphomeDeviceInfo,
|
||||
EntityCategory as EsphomeEntityCategory,
|
||||
|
@ -64,6 +63,7 @@ from .domain_data import DomainData
|
|||
|
||||
# Import config flow so that it's added to the registry
|
||||
from .entry_data import RuntimeEntryData
|
||||
from .enum_mapper import EsphomeEnumMapper
|
||||
|
||||
CONF_DEVICE_NAME = "device_name"
|
||||
CONF_NOISE_PSK = "noise_psk"
|
||||
|
@ -687,41 +687,6 @@ def esphome_state_property(
|
|||
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)
|
||||
|
||||
|
||||
|
|
|
@ -54,12 +54,8 @@ from homeassistant.const import (
|
|||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import (
|
||||
EsphomeEntity,
|
||||
EsphomeEnumMapper,
|
||||
esphome_state_property,
|
||||
platform_async_setup_entry,
|
||||
)
|
||||
from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry
|
||||
from .enum_mapper import EsphomeEnumMapper
|
||||
|
||||
FAN_QUIET = "quiet"
|
||||
|
||||
|
|
39
homeassistant/components/esphome/enum_mapper.py
Normal file
39
homeassistant/components/esphome/enum_mapper.py
Normal 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]
|
|
@ -22,12 +22,8 @@ from homeassistant.util.percentage import (
|
|||
ranged_value_to_percentage,
|
||||
)
|
||||
|
||||
from . import (
|
||||
EsphomeEntity,
|
||||
EsphomeEnumMapper,
|
||||
esphome_state_property,
|
||||
platform_async_setup_entry,
|
||||
)
|
||||
from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry
|
||||
from .enum_mapper import EsphomeEnumMapper
|
||||
|
||||
ORDERED_NAMED_FAN_SPEEDS = [FanSpeed.LOW, FanSpeed.MEDIUM, FanSpeed.HIGH]
|
||||
|
||||
|
|
|
@ -24,12 +24,8 @@ from homeassistant.config_entries import ConfigEntry
|
|||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import (
|
||||
EsphomeEntity,
|
||||
EsphomeEnumMapper,
|
||||
esphome_state_property,
|
||||
platform_async_setup_entry,
|
||||
)
|
||||
from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry
|
||||
from .enum_mapper import EsphomeEnumMapper
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
|
|
@ -11,12 +11,8 @@ from homeassistant.core import HomeAssistant
|
|||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util.enum import try_parse_enum
|
||||
|
||||
from . import (
|
||||
EsphomeEntity,
|
||||
EsphomeEnumMapper,
|
||||
esphome_state_property,
|
||||
platform_async_setup_entry,
|
||||
)
|
||||
from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry
|
||||
from .enum_mapper import EsphomeEnumMapper
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
|
|
@ -24,12 +24,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||
from homeassistant.util import dt
|
||||
from homeassistant.util.enum import try_parse_enum
|
||||
|
||||
from . import (
|
||||
EsphomeEntity,
|
||||
EsphomeEnumMapper,
|
||||
esphome_state_property,
|
||||
platform_async_setup_entry,
|
||||
)
|
||||
from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry
|
||||
from .enum_mapper import EsphomeEnumMapper
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
|
42
tests/components/esphome/test_enum_mapper.py
Normal file
42
tests/components/esphome/test_enum_mapper.py
Normal 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
|
Loading…
Add table
Reference in a new issue