1
0
mirror of https://github.com/home-assistant/core.git synced 2026-07-10 16:19:29 +01:00

Use PEP 695 type parameter syntax for generic classes (#170502)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
Franck Nijhof
2026-05-15 11:53:00 +02:00
committed by GitHub
parent 75a5fcbee7
commit fc7a6b48e2
34 changed files with 78 additions and 77 deletions
@@ -2,7 +2,6 @@
from collections.abc import Callable
from dataclasses import dataclass
from typing import Generic, TypeVar
from airos.data import AirOSDataBaseClass
@@ -20,13 +19,10 @@ from .entity import AirOSEntity
PARALLEL_UPDATES = 0
AirOSDataModel = TypeVar("AirOSDataModel", bound=AirOSDataBaseClass)
@dataclass(frozen=True, kw_only=True)
class AirOSBinarySensorEntityDescription(
class AirOSBinarySensorEntityDescription[AirOSDataModel: AirOSDataBaseClass](
BinarySensorEntityDescription,
Generic[AirOSDataModel],
):
"""Describe an AirOS binary sensor."""
+3 -4
View File
@@ -3,7 +3,6 @@
from collections.abc import Callable
from dataclasses import dataclass
import logging
from typing import Generic, TypeVar
from airos.data import (
AirOSDataBaseClass,
@@ -41,11 +40,11 @@ WIRELESS_ROLE_OPTIONS = [mode.value for mode in DerivedWirelessRole]
PARALLEL_UPDATES = 0
AirOSDataModel = TypeVar("AirOSDataModel", bound=AirOSDataBaseClass)
@dataclass(frozen=True, kw_only=True)
class AirOSSensorEntityDescription(SensorEntityDescription, Generic[AirOSDataModel]):
class AirOSSensorEntityDescription[AirOSDataModel: AirOSDataBaseClass](
SensorEntityDescription
):
"""Describe an AirOS sensor."""
value_fn: Callable[[AirOSDataModel], StateType]
@@ -46,7 +46,7 @@ def get_update_manager(device: BroadlinkDevice[_ApiT]) -> BroadlinkUpdateManager
return update_managers[device.api.type](device)
class BroadlinkUpdateManager(ABC, Generic[_ApiT]):
class BroadlinkUpdateManager(ABC, Generic[_ApiT]): # noqa: UP046
"""Representation of a Broadlink update manager.
Implement this class to manage fetching data from the device and to
+1 -1
View File
@@ -97,7 +97,7 @@ T = TypeVar(
@dataclass(frozen=True, kw_only=True)
class DeconzSensorDescription(SensorEntityDescription, Generic[T]):
class DeconzSensorDescription(SensorEntityDescription, Generic[T]): # noqa: UP046
"""Class describing deCONZ binary sensor entities."""
instance_check: type[T] | None = None
+1 -1
View File
@@ -332,7 +332,7 @@ class EsphomeBaseEntity(Entity):
device_entry: dr.DeviceEntry
class EsphomeEntity(EsphomeBaseEntity, Generic[_InfoT, _StateT]):
class EsphomeEntity(EsphomeBaseEntity, Generic[_InfoT, _StateT]): # noqa: UP046
"""Define an esphome entity."""
_static_info: _InfoT
@@ -33,7 +33,7 @@ T = TypeVar("T", bound=list[LidarrRootFolder] | LidarrQueue | str | LidarrAlbum
type LidarrConfigEntry = ConfigEntry[LidarrData]
class LidarrDataUpdateCoordinator(DataUpdateCoordinator[T], ABC, Generic[T]):
class LidarrDataUpdateCoordinator(DataUpdateCoordinator[T], ABC, Generic[T]): # noqa: UP046
"""Data update coordinator for the Lidarr integration."""
config_entry: LidarrConfigEntry
+4 -2
View File
@@ -47,7 +47,7 @@ def get_modified_description(
@dataclasses.dataclass(frozen=True)
class LidarrSensorEntityDescriptionMixIn(Generic[T]):
class LidarrSensorEntityDescriptionMixIn(Generic[T]): # noqa: UP046
"""Mixin for required keys."""
value_fn: Callable[[T, str], str | int]
@@ -55,7 +55,9 @@ class LidarrSensorEntityDescriptionMixIn(Generic[T]):
@dataclasses.dataclass(frozen=True)
class LidarrSensorEntityDescription(
SensorEntityDescription, LidarrSensorEntityDescriptionMixIn[T], Generic[T]
SensorEntityDescription,
LidarrSensorEntityDescriptionMixIn[T],
Generic[T], # noqa: UP046
):
"""Class to describe a Lidarr sensor."""
@@ -23,7 +23,8 @@ PARALLEL_UPDATES = 0
@dataclass(frozen=True, kw_only=True)
class RobotBinarySensorEntityDescription(
BinarySensorEntityDescription, Generic[_WhiskerEntityT]
BinarySensorEntityDescription,
Generic[_WhiskerEntityT], # noqa: UP046
):
"""A class that describes robot binary sensor entities."""
@@ -18,7 +18,7 @@ PARALLEL_UPDATES = 1
@dataclass(frozen=True, kw_only=True)
class RobotButtonEntityDescription(ButtonEntityDescription, Generic[_WhiskerEntityT]):
class RobotButtonEntityDescription(ButtonEntityDescription, Generic[_WhiskerEntityT]): # noqa: UP046
"""A class that describes robot button entities."""
press_fn: Callable[[_WhiskerEntityT], Coroutine[Any, Any, bool]]
@@ -59,7 +59,8 @@ def get_device_info(whisker_entity: Robot | Pet) -> DeviceInfo:
class LitterRobotEntity(
CoordinatorEntity[LitterRobotDataUpdateCoordinator], Generic[_WhiskerEntityT]
CoordinatorEntity[LitterRobotDataUpdateCoordinator],
Generic[_WhiskerEntityT], # noqa: UP046
):
"""Generic Litter-Robot entity representing common data and methods."""
@@ -22,7 +22,8 @@ _CastTypeT = TypeVar("_CastTypeT", int, float, str)
@dataclass(frozen=True, kw_only=True)
class RobotSelectEntityDescription(
SelectEntityDescription, Generic[_WhiskerEntityT, _CastTypeT]
SelectEntityDescription,
Generic[_WhiskerEntityT, _CastTypeT], # noqa: UP046
):
"""A class that describes robot select entities."""
@@ -144,7 +145,7 @@ async def async_setup_entry(
class LitterRobotSelectEntity(
LitterRobotEntity[_WhiskerEntityT],
SelectEntity,
Generic[_WhiskerEntityT, _CastTypeT],
Generic[_WhiskerEntityT, _CastTypeT], # noqa: UP046
):
"""Litter-Robot Select."""
@@ -36,7 +36,7 @@ def icon_for_gauge_level(gauge_level: int | None = None, offset: int = 0) -> str
@dataclass(frozen=True, kw_only=True)
class RobotSensorEntityDescription(SensorEntityDescription, Generic[_WhiskerEntityT]):
class RobotSensorEntityDescription(SensorEntityDescription, Generic[_WhiskerEntityT]): # noqa: UP046
"""A class that describes robot sensor entities."""
icon_fn: Callable[[Any], str | None] = lambda _: None
@@ -18,7 +18,7 @@ PARALLEL_UPDATES = 1
@dataclass(frozen=True, kw_only=True)
class RobotSwitchEntityDescription(SwitchEntityDescription, Generic[_WhiskerEntityT]):
class RobotSwitchEntityDescription(SwitchEntityDescription, Generic[_WhiskerEntityT]): # noqa: UP046
"""A class that describes robot switch entities."""
entity_category: EntityCategory = EntityCategory.CONFIG
+1 -1
View File
@@ -20,7 +20,7 @@ PARALLEL_UPDATES = 1
@dataclass(frozen=True, kw_only=True)
class RobotTimeEntityDescription(TimeEntityDescription, Generic[_WhiskerEntityT]):
class RobotTimeEntityDescription(TimeEntityDescription, Generic[_WhiskerEntityT]): # noqa: UP046
"""A class that describes robot time entities."""
value_fn: Callable[[_WhiskerEntityT], time | None]
@@ -2,7 +2,6 @@
from collections.abc import Callable
from dataclasses import dataclass
from typing import Generic, TypeVar
from pyprusalink.types import JobInfo, PrinterInfo, PrinterStatus
from pyprusalink.types_legacy import LegacyPrinterStatus
@@ -17,14 +16,13 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .coordinator import PrusaLinkConfigEntry, PrusaLinkUpdateCoordinator
from .entity import PrusaLinkEntity, PrusaLinkEntityDescription
T = TypeVar("T", PrinterStatus, LegacyPrinterStatus, JobInfo, PrinterInfo)
@dataclass(frozen=True, kw_only=True)
class PrusaLinkBinarySensorEntityDescription(
class PrusaLinkBinarySensorEntityDescription[
T: (PrinterStatus, LegacyPrinterStatus, JobInfo, PrinterInfo)
](
BinarySensorEntityDescription,
PrusaLinkEntityDescription,
Generic[T],
):
"""Describes PrusaLink sensor entity."""
+4 -5
View File
@@ -2,7 +2,7 @@
from collections.abc import Callable, Coroutine
from dataclasses import dataclass
from typing import Any, Generic, TypeVar, cast
from typing import Any, cast
from pyprusalink import JobInfo, LegacyPrinterStatus, PrinterStatus, PrusaLink
from pyprusalink.types import Conflict, PrinterState
@@ -15,14 +15,13 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .coordinator import PrusaLinkConfigEntry, PrusaLinkUpdateCoordinator
from .entity import PrusaLinkEntity, PrusaLinkEntityDescription
T = TypeVar("T", PrinterStatus, LegacyPrinterStatus, JobInfo)
@dataclass(frozen=True, kw_only=True)
class PrusaLinkButtonEntityDescription(
class PrusaLinkButtonEntityDescription[
T: (PrinterStatus, LegacyPrinterStatus, JobInfo)
](
ButtonEntityDescription,
PrusaLinkEntityDescription,
Generic[T],
):
"""Describes PrusaLink button entity."""
+4 -5
View File
@@ -3,7 +3,7 @@
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import Generic, TypeVar, cast
from typing import cast
from pyprusalink.types import JobInfo, PrinterInfo, PrinterState, PrinterStatus
from pyprusalink.types_legacy import LegacyPrinterStatus
@@ -29,14 +29,13 @@ from homeassistant.util.variance import ignore_variance
from .coordinator import PrusaLinkConfigEntry, PrusaLinkUpdateCoordinator
from .entity import PrusaLinkEntity, PrusaLinkEntityDescription
T = TypeVar("T", PrinterStatus, LegacyPrinterStatus, JobInfo, PrinterInfo)
@dataclass(frozen=True, kw_only=True)
class PrusaLinkSensorEntityDescription(
class PrusaLinkSensorEntityDescription[
T: (PrinterStatus, LegacyPrinterStatus, JobInfo, PrinterInfo)
](
SensorEntityDescription,
PrusaLinkEntityDescription,
Generic[T],
):
"""Describes PrusaLink sensor entity."""
@@ -55,7 +55,7 @@ class RadarrEvent(CalendarEvent, RadarrEventMixIn):
"""A class to describe a Radarr calendar event."""
class RadarrDataUpdateCoordinator(DataUpdateCoordinator[T], ABC, Generic[T]):
class RadarrDataUpdateCoordinator(DataUpdateCoordinator[T], ABC, Generic[T]): # noqa: UP046
"""Data update coordinator for the Radarr integration."""
config_entry: RadarrConfigEntry
+4 -2
View File
@@ -45,7 +45,7 @@ def get_modified_description(
@dataclasses.dataclass(frozen=True)
class RadarrSensorEntityDescriptionMixIn(Generic[T]):
class RadarrSensorEntityDescriptionMixIn(Generic[T]): # noqa: UP046
"""Mixin for required keys."""
value_fn: Callable[[T, str], str | int | datetime]
@@ -53,7 +53,9 @@ class RadarrSensorEntityDescriptionMixIn(Generic[T]):
@dataclasses.dataclass(frozen=True)
class RadarrSensorEntityDescription(
SensorEntityDescription, RadarrSensorEntityDescriptionMixIn[T], Generic[T]
SensorEntityDescription,
RadarrSensorEntityDescriptionMixIn[T],
Generic[T], # noqa: UP046
):
"""Class to describe a Radarr sensor."""
@@ -34,7 +34,9 @@ PARALLEL_UPDATES = 0
@dataclass(frozen=True, kw_only=True)
class RingBinarySensorEntityDescription(
BinarySensorEntityDescription, RingEntityDescription, Generic[RingDeviceT]
BinarySensorEntityDescription,
RingEntityDescription,
Generic[RingDeviceT], # noqa: UP046
):
"""Describes Ring binary sensor entity."""
+1 -1
View File
@@ -44,7 +44,7 @@ _LOGGER = logging.getLogger(__name__)
@dataclass(frozen=True, kw_only=True)
class RingCameraEntityDescription(CameraEntityDescription, Generic[RingDeviceT]):
class RingCameraEntityDescription(CameraEntityDescription, Generic[RingDeviceT]): # noqa: UP046
"""Base class for event entity description."""
exists_fn: Callable[[RingDoorBell], bool]
+1 -1
View File
@@ -24,7 +24,7 @@ PARALLEL_UPDATES = 0
@dataclass(frozen=True, kw_only=True)
class RingEventEntityDescription(EventEntityDescription, Generic[RingDeviceT]):
class RingEventEntityDescription(EventEntityDescription, Generic[RingDeviceT]): # noqa: UP046
"""Base class for event entity description."""
capability: RingCapability
+1 -1
View File
@@ -43,7 +43,7 @@ async def async_setup_entry(
@dataclass(frozen=True, kw_only=True)
class RingNumberEntityDescription(NumberEntityDescription, Generic[RingDeviceT]):
class RingNumberEntityDescription(NumberEntityDescription, Generic[RingDeviceT]): # noqa: UP046
"""Describes Ring number entity."""
value_fn: Callable[[RingDeviceT], StateType]
+3 -1
View File
@@ -135,7 +135,9 @@ def _get_last_event_attrs(
@dataclass(frozen=True, kw_only=True)
class RingSensorEntityDescription(
SensorEntityDescription, RingEntityDescription, Generic[RingDeviceT]
SensorEntityDescription,
RingEntityDescription,
Generic[RingDeviceT], # noqa: UP046
):
"""Describes Ring sensor entity."""
+3 -1
View File
@@ -43,7 +43,9 @@ PARALLEL_UPDATES = 1
@dataclass(frozen=True, kw_only=True)
class RingSirenEntityDescription(
SirenEntityDescription, RingEntityDescription, Generic[RingDeviceT]
SirenEntityDescription,
RingEntityDescription,
Generic[RingDeviceT], # noqa: UP046
):
"""Describes a Ring siren entity."""
+3 -1
View File
@@ -36,7 +36,9 @@ IN_HOME_CHIME_IS_PRESENT = {v for k, v in DOORBELL_EXISTING_TYPE.items() if k !=
@dataclass(frozen=True, kw_only=True)
class RingSwitchEntityDescription(
SwitchEntityDescription, RingEntityDescription, Generic[RingDeviceT]
SwitchEntityDescription,
RingEntityDescription,
Generic[RingDeviceT], # noqa: UP046
):
"""Describes a Ring switch entity."""
+4 -6
View File
@@ -2,7 +2,7 @@
from collections.abc import Callable
from dataclasses import dataclass
from typing import Any, Generic, TypeVar
from typing import Any
from pysmarlaapi.federwiege.services.classes import Property
from pysmarlaapi.federwiege.services.types import SpringStatus
@@ -23,12 +23,10 @@ from .entity import SmarlaBaseEntity, SmarlaEntityDescription
PARALLEL_UPDATES = 0
_VT = TypeVar("_VT")
@dataclass(frozen=True, kw_only=True)
class SmarlaSensorEntityDescription(
SmarlaEntityDescription, SensorEntityDescription, Generic[_VT]
class SmarlaSensorEntityDescription[_VT](
SmarlaEntityDescription, SensorEntityDescription
):
"""Class describing Swing2Sleep Smarla sensor entities."""
@@ -110,7 +108,7 @@ async def async_setup_entry(
async_add_entities(SmarlaSensor(federwiege, desc) for desc in SENSORS)
class SmarlaSensor(SmarlaBaseEntity, SensorEntity, Generic[_VT]):
class SmarlaSensor[_VT](SmarlaBaseEntity, SensorEntity):
"""Representation of Smarla sensor."""
entity_description: SmarlaSensorEntityDescription[_VT]
+1 -1
View File
@@ -29,7 +29,7 @@ from .entity import SonarrEntity
@dataclass(frozen=True)
class SonarrSensorEntityDescriptionMixIn(Generic[SonarrDataT]):
class SonarrSensorEntityDescriptionMixIn(Generic[SonarrDataT]): # noqa: UP046
"""Mixin for Sonarr sensor."""
attributes_fn: Callable[[SonarrDataT], dict[str, str]]
@@ -1,7 +1,7 @@
"""Tesla Fleet parent entity class."""
from abc import abstractmethod
from typing import Any, Generic, TypeVar
from typing import Any
from tesla_fleet_api.const import Scope
from tesla_fleet_api.tesla.energysite import EnergySite
@@ -21,17 +21,14 @@ from .coordinator import (
from .helpers import wake_up_vehicle
from .models import TeslaFleetEnergyData, TeslaFleetVehicleData
_ApiT = TypeVar("_ApiT", bound=VehicleFleet | EnergySite)
class TeslaFleetEntity(
class TeslaFleetEntity[_ApiT: VehicleFleet | EnergySite](
CoordinatorEntity[
TeslaFleetVehicleDataCoordinator
| TeslaFleetEnergySiteLiveCoordinator
| TeslaFleetEnergySiteHistoryCoordinator
| TeslaFleetEnergySiteInfoCoordinator
],
Generic[_ApiT],
]
):
"""Parent class for all TeslaFleet entities."""
+12 -11
View File
@@ -3,7 +3,7 @@
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from functools import partial
from typing import Any, Generic, TypeVar
from typing import Any
from tplink_omada_client import (
GatewayPortSettings,
@@ -38,10 +38,6 @@ from .controller import OmadaGatewayCoordinator, OmadaSwitchPortCoordinator
from .coordinator import OmadaCoordinator
from .entity import OmadaDeviceEntity
TPort = TypeVar("TPort")
TDevice = TypeVar("TDevice", bound="OmadaDevice")
TCoordinator = TypeVar("TCoordinator", bound="OmadaCoordinator[Any]")
PARALLEL_UPDATES = 0
@@ -132,9 +128,11 @@ def _get_switch_port_base_name(port: OmadaSwitchPortDetails) -> str:
@dataclass(frozen=True, kw_only=True)
class OmadaDevicePortSwitchEntityDescription(
SwitchEntityDescription, Generic[TCoordinator, TDevice, TPort]
):
class OmadaDevicePortSwitchEntityDescription[
TCoordinator: OmadaCoordinator[Any],
TDevice: OmadaDevice,
TPort,
](SwitchEntityDescription):
"""Entity description for a toggle switch derived from a network port on an Omada device."""
exists_func: Callable[[TDevice, TPort], bool] = lambda _, p: True
@@ -262,12 +260,15 @@ GATEWAY_PORT_CONFIG_SWITCHES: list[OmadaGatewayPortConfigSwitchEntityDescription
]
class OmadaDevicePortSwitchEntity(
class OmadaDevicePortSwitchEntity[
TCoordinator: OmadaCoordinator[Any],
TDevice: OmadaDevice,
TPort,
](
OmadaDeviceEntity[TCoordinator],
SwitchEntity,
Generic[TCoordinator, TDevice, TPort],
):
"""Generic toggle switch entity for a Netork Port of an Omada Device."""
"""Generic toggle switch entity for a Network Port of an Omada Device."""
entity_description: OmadaDevicePortSwitchEntityDescription[
TCoordinator, TDevice, TPort
@@ -369,7 +369,7 @@ class EventEntityMixin(ProtectDeviceEntity):
@dataclass(frozen=True, kw_only=True)
class ProtectEntityDescription(EntityDescription, Generic[T]):
class ProtectEntityDescription(EntityDescription, Generic[T]): # noqa: UP046
"""Base class for protect entity descriptions."""
ufp_required_field: str | None = None
+2 -2
View File
@@ -91,7 +91,7 @@ _TypedDictT = TypeVar("_TypedDictT", bound=Mapping[str, Any])
@dataclass(slots=True, frozen=True)
class _KeyedEventTracker(Generic[_TypedDictT]):
class _KeyedEventTracker(Generic[_TypedDictT]): # noqa: UP046
"""Class to track events by key."""
key: HassKey[_KeyedEventData[_TypedDictT]]
@@ -115,7 +115,7 @@ class _KeyedEventTracker(Generic[_TypedDictT]):
@dataclass(slots=True, frozen=True)
class _KeyedEventData(Generic[_TypedDictT]):
class _KeyedEventData(Generic[_TypedDictT]): # noqa: UP046
"""Class to track data for events by key."""
listener: CALLBACK_TYPE
+1 -1
View File
@@ -11,7 +11,7 @@ __all__ = [
_T = TypeVar("_T") # needs to be invariant
class _Key(Generic[_T]):
class _Key(Generic[_T]): # noqa: UP046
"""Base class for Hass key types. At runtime delegated to str."""
def __init__(self, value: str, /) -> None: ...
-1
View File
@@ -823,7 +823,6 @@ ignore = [
"TRY003", # Avoid specifying long messages outside the exception class
"TRY400", # Use `logging.exception` instead of `logging.error`
"UP046", # Non PEP 695 generic class
"UP047", # Non PEP 696 generic function
"UP049", # Avoid private type parameter names