Allow inheriting base component entity descriptions in frozen dataclasses (#105512)

Co-authored-by: J. Nick Koston <nick@koston.org>
pull/105841/head^2
Erik Montnemery 2023-12-16 10:33:50 +01:00 committed by GitHub
parent 47f8e08261
commit 104bcc64b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 35 additions and 85 deletions

View File

@ -1,7 +1,6 @@
"""Component to interface with an alarm control panel."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
import logging
from typing import Any, Final, final
@ -121,8 +120,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class AlarmControlPanelEntityDescription(EntityDescription):
class AlarmControlPanelEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes alarm control panel entities."""

View File

@ -1,7 +1,6 @@
"""Component to interface with binary sensors."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
from enum import StrEnum
import logging
@ -176,8 +175,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class BinarySensorEntityDescription(EntityDescription):
class BinarySensorEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes binary sensor entities."""
device_class: BinarySensorDeviceClass | None = None

View File

@ -93,7 +93,10 @@ def deserialize_entity_description(
descriptions_class: type[EntityDescription], data: dict[str, Any]
) -> EntityDescription:
"""Deserialize an entity description."""
# pylint: disable=protected-access
result: dict[str, Any] = {}
if hasattr(descriptions_class, "_dataclass"):
descriptions_class = descriptions_class._dataclass
for field in cached_fields(descriptions_class):
field_name = field.name
# It would be nice if field.type returned the actual

View File

@ -1,7 +1,6 @@
"""Component to pressing a button as platforms."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime, timedelta
from enum import StrEnum
import logging
@ -73,8 +72,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class ButtonEntityDescription(EntityDescription):
class ButtonEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes button entities."""
device_class: ButtonDeviceClass | None = None

View File

@ -5,7 +5,7 @@ import asyncio
import collections
from collections.abc import Awaitable, Callable, Iterable
from contextlib import suppress
from dataclasses import asdict, dataclass
from dataclasses import asdict
from datetime import datetime, timedelta
from enum import IntFlag
from functools import partial
@ -132,8 +132,7 @@ CAMERA_SERVICE_RECORD: Final = {
}
@dataclass
class CameraEntityDescription(EntityDescription):
class CameraEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes camera entities."""

View File

@ -1,7 +1,6 @@
"""Provides functionality to interact with climate devices."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
import functools as ft
import logging
@ -201,8 +200,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class ClimateEntityDescription(EntityDescription):
class ClimateEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes climate entities."""

View File

@ -2,7 +2,6 @@
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from datetime import timedelta
from enum import IntFlag, StrEnum
import functools as ft
@ -212,8 +211,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class CoverEntityDescription(EntityDescription):
class CoverEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes cover entities."""
device_class: CoverDeviceClass | None = None

View File

@ -1,7 +1,6 @@
"""Component to allow setting date as platforms."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import date, timedelta
import logging
from typing import final
@ -62,8 +61,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class DateEntityDescription(EntityDescription):
class DateEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes date entities."""

View File

@ -1,7 +1,6 @@
"""Component to allow setting date/time as platforms."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import UTC, datetime, timedelta
import logging
from typing import final
@ -71,8 +70,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class DateTimeEntityDescription(EntityDescription):
class DateTimeEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes date/time entities."""

View File

@ -71,8 +71,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class EventEntityDescription(EntityDescription):
class EventEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes event entities."""
device_class: EventDeviceClass | None = None

View File

@ -1,7 +1,6 @@
"""Provides functionality to interact with fans."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
from enum import IntFlag
import functools as ft
@ -187,8 +186,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class FanEntityDescription(ToggleEntityDescription):
class FanEntityDescription(ToggleEntityDescription, frozen_or_thawed=True):
"""A class that describes fan entities."""

View File

@ -1,7 +1,6 @@
"""Provides functionality to interact with humidifier devices."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
from enum import StrEnum
import logging
@ -124,8 +123,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class HumidifierEntityDescription(ToggleEntityDescription):
class HumidifierEntityDescription(ToggleEntityDescription, frozen_or_thawed=True):
"""A class that describes humidifier entities."""
device_class: HumidifierDeviceClass | None = None

View File

@ -44,8 +44,7 @@ _RND: Final = SystemRandom()
GET_IMAGE_TIMEOUT: Final = 10
@dataclass
class ImageEntityDescription(EntityDescription):
class ImageEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes image entities."""

View File

@ -2,7 +2,6 @@
from __future__ import annotations
import asyncio
from dataclasses import dataclass
from datetime import timedelta
from enum import StrEnum
import logging
@ -120,8 +119,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
return True
@dataclass
class ImageProcessingEntityDescription(EntityDescription):
class ImageProcessingEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes sensor entities."""
device_class: ImageProcessingDeviceClass | None = None

View File

@ -1,7 +1,6 @@
"""The lawn mower integration."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
import logging
from typing import final
@ -65,8 +64,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class LawnMowerEntityEntityDescription(EntityDescription):
class LawnMowerEntityEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes lawn mower entities."""

View File

@ -816,8 +816,7 @@ class Profiles:
params.setdefault(ATTR_TRANSITION, profile.transition)
@dataclasses.dataclass
class LightEntityDescription(ToggleEntityDescription):
class LightEntityDescription(ToggleEntityDescription, frozen_or_thawed=True):
"""A class that describes binary sensor entities."""

View File

@ -1,7 +1,6 @@
"""Component to interface with locks that can be controlled remotely."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
from enum import IntFlag
import functools as ft
@ -101,8 +100,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class LockEntityDescription(EntityDescription):
class LockEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes lock entities."""

View File

@ -5,7 +5,6 @@ import asyncio
import collections
from collections.abc import Callable
from contextlib import suppress
from dataclasses import dataclass
import datetime as dt
from enum import StrEnum
import functools as ft
@ -449,8 +448,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class MediaPlayerEntityDescription(EntityDescription):
class MediaPlayerEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes media player entities."""
device_class: MediaPlayerDeviceClass | None = None

View File

@ -120,8 +120,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclasses.dataclass
class NumberEntityDescription(EntityDescription):
class NumberEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes number entities."""
device_class: NumberDeviceClass | None = None

View File

@ -2,7 +2,6 @@
from __future__ import annotations
from collections.abc import Iterable
from dataclasses import dataclass
from datetime import timedelta
from enum import IntFlag
import functools as ft
@ -155,8 +154,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class RemoteEntityDescription(ToggleEntityDescription):
class RemoteEntityDescription(ToggleEntityDescription, frozen_or_thawed=True):
"""A class that describes remote entities."""

View File

@ -1,7 +1,6 @@
"""Component to allow selecting an option from a list as platforms."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
import logging
from typing import Any, final
@ -118,8 +117,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class SelectEntityDescription(EntityDescription):
class SelectEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes select entities."""
options: list[str] | None = None

View File

@ -136,8 +136,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class SensorEntityDescription(EntityDescription):
class SensorEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes sensor entities."""
device_class: SensorDeviceClass | None = None

View File

@ -1,7 +1,6 @@
"""Component to interface with various sirens/chimes."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
import logging
from typing import Any, TypedDict, cast, final
@ -149,8 +148,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class SirenEntityDescription(ToggleEntityDescription):
class SirenEntityDescription(ToggleEntityDescription, frozen_or_thawed=True):
"""A class that describes siren entities."""
available_tones: list[int | str] | dict[int, str] | None = None

View File

@ -1,7 +1,6 @@
"""Component to interface with switches that can be controlled remotely."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
from enum import StrEnum
import logging
@ -89,8 +88,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class SwitchEntityDescription(ToggleEntityDescription):
class SwitchEntityDescription(ToggleEntityDescription, frozen_or_thawed=True):
"""A class that describes switch entities."""
device_class: SwitchDeviceClass | None = None

View File

@ -98,8 +98,7 @@ class TextMode(StrEnum):
TEXT = "text"
@dataclass
class TextEntityDescription(EntityDescription):
class TextEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes text entities."""
native_min: int = 0

View File

@ -1,7 +1,6 @@
"""Component to allow setting time as platforms."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import time, timedelta
import logging
from typing import final
@ -62,8 +61,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class TimeEntityDescription(EntityDescription):
class TimeEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes time entities."""

View File

@ -1,7 +1,6 @@
"""Component to allow for providing device or service updates."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
from enum import StrEnum
from functools import lru_cache
@ -175,8 +174,7 @@ async def async_clear_skipped(entity: UpdateEntity, service_call: ServiceCall) -
await entity.async_clear_skipped()
@dataclass
class UpdateEntityDescription(EntityDescription):
class UpdateEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes update entities."""
device_class: UpdateDeviceClass | None = None

View File

@ -3,7 +3,6 @@ from __future__ import annotations
import asyncio
from collections.abc import Mapping
from dataclasses import dataclass
from datetime import timedelta
from enum import IntFlag
from functools import partial
@ -367,8 +366,7 @@ class _BaseVacuum(Entity):
)
@dataclass
class VacuumEntityDescription(ToggleEntityDescription):
class VacuumEntityDescription(ToggleEntityDescription, frozen_or_thawed=True):
"""A class that describes vacuum entities."""
@ -490,8 +488,7 @@ class VacuumEntity(_BaseVacuum, ToggleEntity):
await self.hass.async_add_executor_job(partial(self.start_pause, **kwargs))
@dataclass
class StateVacuumEntityDescription(EntityDescription):
class StateVacuumEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes vacuum entities."""

View File

@ -2,7 +2,6 @@
from __future__ import annotations
from collections.abc import Mapping
from dataclasses import dataclass
from datetime import timedelta
from enum import IntFlag
import functools as ft
@ -156,8 +155,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class WaterHeaterEntityEntityDescription(EntityDescription):
class WaterHeaterEntityEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes water heater entities."""

View File

@ -5,7 +5,6 @@ import abc
import asyncio
from collections.abc import Callable, Iterable
from contextlib import suppress
from dataclasses import dataclass
from datetime import timedelta
from functools import partial
import logging
@ -251,8 +250,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class WeatherEntityDescription(EntityDescription):
class WeatherEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes weather entities."""

View File

@ -1313,8 +1313,7 @@ class Entity(ABC):
)
@dataclasses.dataclass(slots=True)
class ToggleEntityDescription(EntityDescription):
class ToggleEntityDescription(EntityDescription, frozen_or_thawed=True):
"""A class that describes toggle entities."""