diff --git a/homeassistant/helpers/config_entry_flow.py b/homeassistant/helpers/config_entry_flow.py index f2247e533a8..b047e1aef81 100644 --- a/homeassistant/helpers/config_entry_flow.py +++ b/homeassistant/helpers/config_entry_flow.py @@ -4,7 +4,7 @@ from __future__ import annotations from collections.abc import Awaitable, Callable import logging -from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast +from typing import TYPE_CHECKING, Any, cast from homeassistant import config_entries from homeassistant.components import onboarding @@ -22,13 +22,12 @@ if TYPE_CHECKING: from .service_info.mqtt import MqttServiceInfo -_R = TypeVar("_R", bound="Awaitable[bool] | bool") -DiscoveryFunctionType = Callable[[HomeAssistant], _R] +type DiscoveryFunctionType[_R] = Callable[[HomeAssistant], _R] _LOGGER = logging.getLogger(__name__) -class DiscoveryFlowHandler(config_entries.ConfigFlow, Generic[_R]): +class DiscoveryFlowHandler[_R: Awaitable[bool] | bool](config_entries.ConfigFlow): """Handle a discovery config flow.""" VERSION = 1 diff --git a/homeassistant/helpers/device_registry.py b/homeassistant/helpers/device_registry.py index 51896ac2be9..e39676146d6 100644 --- a/homeassistant/helpers/device_registry.py +++ b/homeassistant/helpers/device_registry.py @@ -7,7 +7,7 @@ from enum import StrEnum from functools import cached_property, lru_cache, partial import logging import time -from typing import TYPE_CHECKING, Any, Literal, TypedDict, TypeVar +from typing import TYPE_CHECKING, Any, Literal, TypedDict import attr from yarl import URL @@ -449,10 +449,9 @@ class DeviceRegistryStore(storage.Store[dict[str, list[dict[str, Any]]]]): return old_data -_EntryTypeT = TypeVar("_EntryTypeT", DeviceEntry, DeletedDeviceEntry) - - -class DeviceRegistryItems(BaseRegistryItems[_EntryTypeT]): +class DeviceRegistryItems[_EntryTypeT: (DeviceEntry, DeletedDeviceEntry)]( + BaseRegistryItems[_EntryTypeT] +): """Container for device registry items, maps device id -> entry. Maintains two additional indexes: diff --git a/homeassistant/helpers/normalized_name_base_registry.py b/homeassistant/helpers/normalized_name_base_registry.py index f14d99b7831..1cffac9ffc5 100644 --- a/homeassistant/helpers/normalized_name_base_registry.py +++ b/homeassistant/helpers/normalized_name_base_registry.py @@ -2,7 +2,6 @@ from dataclasses import dataclass from functools import lru_cache -from typing import TypeVar from .registry import BaseRegistryItems @@ -15,16 +14,15 @@ class NormalizedNameBaseRegistryEntry: normalized_name: str -_VT = TypeVar("_VT", bound=NormalizedNameBaseRegistryEntry) - - @lru_cache(maxsize=1024) def normalize_name(name: str) -> str: """Normalize a name by removing whitespace and case folding.""" return name.casefold().replace(" ", "") -class NormalizedNameBaseRegistryItems(BaseRegistryItems[_VT]): +class NormalizedNameBaseRegistryItems[_VT: NormalizedNameBaseRegistryEntry]( + BaseRegistryItems[_VT] +): """Base container for normalized name registry items, maps key -> entry. Maintains an additional index: diff --git a/homeassistant/helpers/registry.py b/homeassistant/helpers/registry.py index 832f50661ae..9791b03c5cb 100644 --- a/homeassistant/helpers/registry.py +++ b/homeassistant/helpers/registry.py @@ -5,7 +5,7 @@ from __future__ import annotations from abc import ABC, abstractmethod from collections import UserDict from collections.abc import Mapping, Sequence, ValuesView -from typing import TYPE_CHECKING, Any, Generic, Literal, TypeVar +from typing import TYPE_CHECKING, Any, Literal from homeassistant.core import CoreState, HomeAssistant, callback @@ -16,11 +16,7 @@ SAVE_DELAY = 10 SAVE_DELAY_LONG = 180 -_DataT = TypeVar("_DataT") -_StoreDataT = TypeVar("_StoreDataT", bound=Mapping[str, Any] | Sequence[Any]) - - -class BaseRegistryItems(UserDict[str, _DataT], ABC): +class BaseRegistryItems[_DataT](UserDict[str, _DataT], ABC): """Base class for registry items.""" data: dict[str, _DataT] @@ -65,7 +61,7 @@ class BaseRegistryItems(UserDict[str, _DataT], ABC): super().__delitem__(key) -class BaseRegistry(ABC, Generic[_StoreDataT]): +class BaseRegistry[_StoreDataT: Mapping[str, Any] | Sequence[Any]](ABC): """Class to implement a registry.""" hass: HomeAssistant diff --git a/homeassistant/helpers/selector.py b/homeassistant/helpers/selector.py index 01521556453..c103999bd33 100644 --- a/homeassistant/helpers/selector.py +++ b/homeassistant/helpers/selector.py @@ -6,7 +6,7 @@ from collections.abc import Callable, Mapping, Sequence from enum import StrEnum from functools import cache import importlib -from typing import Any, Generic, Literal, Required, TypedDict, TypeVar, cast +from typing import Any, Literal, Required, TypedDict, cast from uuid import UUID import voluptuous as vol @@ -21,8 +21,6 @@ from . import config_validation as cv SELECTORS: decorator.Registry[str, type[Selector]] = decorator.Registry() -_T = TypeVar("_T", bound=Mapping[str, Any]) - def _get_selector_class(config: Any) -> type[Selector]: """Get selector class type.""" @@ -62,7 +60,7 @@ def validate_selector(config: Any) -> dict: } -class Selector(Generic[_T]): +class Selector[_T: Mapping[str, Any]]: """Base class for selectors.""" CONFIG_SCHEMA: Callable diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index 7d5a15f41b2..cec0f7ba747 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -9,7 +9,7 @@ from enum import Enum from functools import cache, partial import logging from types import ModuleType -from typing import TYPE_CHECKING, Any, Generic, TypedDict, TypeGuard, TypeVar, cast +from typing import TYPE_CHECKING, Any, TypedDict, TypeGuard, cast import voluptuous as vol @@ -79,8 +79,6 @@ ALL_SERVICE_DESCRIPTIONS_CACHE: HassKey[ tuple[set[tuple[str, str]], dict[str, dict[str, Any]]] ] = HassKey("all_service_descriptions_cache") -_T = TypeVar("_T") - @cache def _base_components() -> dict[str, ModuleType]: @@ -1153,7 +1151,7 @@ def verify_domain_control( return decorator -class ReloadServiceHelper(Generic[_T]): +class ReloadServiceHelper[_T]: """Helper for reload services. The helper has the following purposes: diff --git a/homeassistant/util/decorator.py b/homeassistant/util/decorator.py index 5bd817de103..04c1ec5e47b 100644 --- a/homeassistant/util/decorator.py +++ b/homeassistant/util/decorator.py @@ -3,13 +3,10 @@ from __future__ import annotations from collections.abc import Callable, Hashable -from typing import Any, TypeVar - -_KT = TypeVar("_KT", bound=Hashable) -_VT = TypeVar("_VT", bound=Callable[..., Any]) +from typing import Any -class Registry(dict[_KT, _VT]): +class Registry[_KT: Hashable, _VT: Callable[..., Any]](dict[_KT, _VT]): """Registry of items.""" def register(self, name: _KT) -> Callable[[_VT], _VT]: diff --git a/homeassistant/util/limited_size_dict.py b/homeassistant/util/limited_size_dict.py index 6166a6c8239..8f0d9315855 100644 --- a/homeassistant/util/limited_size_dict.py +++ b/homeassistant/util/limited_size_dict.py @@ -3,13 +3,10 @@ from __future__ import annotations from collections import OrderedDict -from typing import Any, TypeVar - -_KT = TypeVar("_KT") -_VT = TypeVar("_VT") +from typing import Any -class LimitedSizeDict(OrderedDict[_KT, _VT]): +class LimitedSizeDict[_KT, _VT](OrderedDict[_KT, _VT]): """OrderedDict limited in size.""" def __init__(self, *args: Any, **kwds: Any) -> None: diff --git a/homeassistant/util/read_only_dict.py b/homeassistant/util/read_only_dict.py index 90245ce7ca9..59d10b015a5 100644 --- a/homeassistant/util/read_only_dict.py +++ b/homeassistant/util/read_only_dict.py @@ -1,6 +1,6 @@ """Read only dictionary.""" -from typing import Any, TypeVar +from typing import Any def _readonly(*args: Any, **kwargs: Any) -> Any: @@ -8,11 +8,7 @@ def _readonly(*args: Any, **kwargs: Any) -> Any: raise RuntimeError("Cannot modify ReadOnlyDict") -_KT = TypeVar("_KT") -_VT = TypeVar("_VT") - - -class ReadOnlyDict(dict[_KT, _VT]): +class ReadOnlyDict[_KT, _VT](dict[_KT, _VT]): """Read only version of dict that is compatible with dict types.""" __setitem__ = _readonly diff --git a/homeassistant/util/signal_type.py b/homeassistant/util/signal_type.py index e2730c969c4..c9b74411ae0 100644 --- a/homeassistant/util/signal_type.py +++ b/homeassistant/util/signal_type.py @@ -3,13 +3,11 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Any, Generic, TypeVarTuple - -_Ts = TypeVarTuple("_Ts") +from typing import Any @dataclass(frozen=True) -class _SignalTypeBase(Generic[*_Ts]): +class _SignalTypeBase[*_Ts]: """Generic base class for SignalType.""" name: str @@ -30,12 +28,12 @@ class _SignalTypeBase(Generic[*_Ts]): @dataclass(frozen=True, eq=False) -class SignalType(_SignalTypeBase[*_Ts]): +class SignalType[*_Ts](_SignalTypeBase[*_Ts]): """Generic string class for signal to improve typing.""" @dataclass(frozen=True, eq=False) -class SignalTypeFormat(_SignalTypeBase[*_Ts]): +class SignalTypeFormat[*_Ts](_SignalTypeBase[*_Ts]): """Generic string class for signal. Requires call to 'format' before use.""" def format(self, *args: Any, **kwargs: Any) -> SignalType[*_Ts]: diff --git a/tests/common.py b/tests/common.py index 55c448fdad2..b77ab9afc5b 100644 --- a/tests/common.py +++ b/tests/common.py @@ -17,7 +17,7 @@ import pathlib import threading import time from types import FrameType, ModuleType -from typing import Any, NoReturn, TypeVar +from typing import Any, NoReturn from unittest.mock import AsyncMock, Mock, patch from aiohttp.test_utils import unused_port as get_test_instance_port # noqa: F401 @@ -199,10 +199,7 @@ def get_test_home_assistant() -> Generator[HomeAssistant, None, None]: loop.close() -_T = TypeVar("_T", bound=Mapping[str, Any] | Sequence[Any]) - - -class StoreWithoutWriteLoad(storage.Store[_T]): +class StoreWithoutWriteLoad[_T: (Mapping[str, Any] | Sequence[Any])](storage.Store[_T]): """Fake store that does not write or load. Used for testing.""" async def async_save(self, *args: Any, **kwargs: Any) -> None: