Use PEP 695 for decorator typing with type aliases (2) (#117663)

This commit is contained in:
Marc Mueller 2024-05-18 11:41:46 +02:00 committed by GitHub
parent d65437e347
commit 907b9c42e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 41 additions and 55 deletions

View file

@ -5,7 +5,7 @@ from __future__ import annotations
from collections.abc import Awaitable, Callable, Coroutine from collections.abc import Awaitable, Callable, Coroutine
import functools import functools
import logging import logging
from typing import Any, Concatenate, ParamSpec, TypeVar from typing import Any, Concatenate
import aiohttp import aiohttp
from async_upnp_client.client import UpnpError from async_upnp_client.client import UpnpError
@ -28,10 +28,6 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import ATTR_PIN_INDEX, DOMAIN, SERVICE_INVOKE_PIN from .const import ATTR_PIN_INDEX, DOMAIN, SERVICE_INVOKE_PIN
_OpenhomeDeviceT = TypeVar("_OpenhomeDeviceT", bound="OpenhomeDevice")
_R = TypeVar("_R")
_P = ParamSpec("_P")
SUPPORT_OPENHOME = ( SUPPORT_OPENHOME = (
MediaPlayerEntityFeature.SELECT_SOURCE MediaPlayerEntityFeature.SELECT_SOURCE
| MediaPlayerEntityFeature.TURN_OFF | MediaPlayerEntityFeature.TURN_OFF
@ -65,13 +61,13 @@ async def async_setup_entry(
) )
_FuncType = Callable[Concatenate[_OpenhomeDeviceT, _P], Awaitable[_R]] type _FuncType[_T, **_P, _R] = Callable[Concatenate[_T, _P], Awaitable[_R]]
_ReturnFuncType = Callable[ type _ReturnFuncType[_T, **_P, _R] = Callable[
Concatenate[_OpenhomeDeviceT, _P], Coroutine[Any, Any, _R | None] Concatenate[_T, _P], Coroutine[Any, Any, _R | None]
] ]
def catch_request_errors() -> ( def catch_request_errors[_OpenhomeDeviceT: OpenhomeDevice, **_P, _R]() -> (
Callable[ Callable[
[_FuncType[_OpenhomeDeviceT, _P, _R]], _ReturnFuncType[_OpenhomeDeviceT, _P, _R] [_FuncType[_OpenhomeDeviceT, _P, _R]], _ReturnFuncType[_OpenhomeDeviceT, _P, _R]
] ]

View file

@ -12,7 +12,7 @@ from itertools import islice
import logging import logging
import os import os
import time import time
from typing import TYPE_CHECKING, Any, Concatenate, NoReturn, ParamSpec, TypeVar from typing import TYPE_CHECKING, Any, Concatenate, NoReturn
from awesomeversion import ( from awesomeversion import (
AwesomeVersion, AwesomeVersion,
@ -61,9 +61,6 @@ if TYPE_CHECKING:
from . import Recorder from . import Recorder
_RecorderT = TypeVar("_RecorderT", bound="Recorder")
_P = ParamSpec("_P")
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
RETRIES = 3 RETRIES = 3
@ -628,18 +625,20 @@ def _is_retryable_error(instance: Recorder, err: OperationalError) -> bool:
) )
_FuncType = Callable[Concatenate[_RecorderT, _P], bool] type _FuncType[_T, **_P, _R] = Callable[Concatenate[_T, _P], _R]
def retryable_database_job( def retryable_database_job[_RecorderT: Recorder, **_P](
description: str, description: str,
) -> Callable[[_FuncType[_RecorderT, _P]], _FuncType[_RecorderT, _P]]: ) -> Callable[[_FuncType[_RecorderT, _P, bool]], _FuncType[_RecorderT, _P, bool]]:
"""Try to execute a database job. """Try to execute a database job.
The job should return True if it finished, and False if it needs to be rescheduled. The job should return True if it finished, and False if it needs to be rescheduled.
""" """
def decorator(job: _FuncType[_RecorderT, _P]) -> _FuncType[_RecorderT, _P]: def decorator(
job: _FuncType[_RecorderT, _P, bool],
) -> _FuncType[_RecorderT, _P, bool]:
@functools.wraps(job) @functools.wraps(job)
def wrapper(instance: _RecorderT, *args: _P.args, **kwargs: _P.kwargs) -> bool: def wrapper(instance: _RecorderT, *args: _P.args, **kwargs: _P.kwargs) -> bool:
try: try:
@ -664,12 +663,9 @@ def retryable_database_job(
return decorator return decorator
_WrappedFuncType = Callable[Concatenate[_RecorderT, _P], None] def database_job_retry_wrapper[_RecorderT: Recorder, **_P](
def database_job_retry_wrapper(
description: str, attempts: int = 5 description: str, attempts: int = 5
) -> Callable[[_WrappedFuncType[_RecorderT, _P]], _WrappedFuncType[_RecorderT, _P]]: ) -> Callable[[_FuncType[_RecorderT, _P, None]], _FuncType[_RecorderT, _P, None]]:
"""Try to execute a database job multiple times. """Try to execute a database job multiple times.
This wrapper handles InnoDB deadlocks and lock timeouts. This wrapper handles InnoDB deadlocks and lock timeouts.
@ -679,8 +675,8 @@ def database_job_retry_wrapper(
""" """
def decorator( def decorator(
job: _WrappedFuncType[_RecorderT, _P], job: _FuncType[_RecorderT, _P, None],
) -> _WrappedFuncType[_RecorderT, _P]: ) -> _FuncType[_RecorderT, _P, None]:
@functools.wraps(job) @functools.wraps(job)
def wrapper(instance: _RecorderT, *args: _P.args, **kwargs: _P.kwargs) -> None: def wrapper(instance: _RecorderT, *args: _P.args, **kwargs: _P.kwargs) -> None:
for attempt in range(attempts): for attempt in range(attempts):

View file

@ -4,7 +4,7 @@ from __future__ import annotations
from collections.abc import Awaitable, Callable, Coroutine from collections.abc import Awaitable, Callable, Coroutine
from functools import wraps from functools import wraps
from typing import Any, Concatenate, ParamSpec, TypeVar from typing import Any, Concatenate
from rokuecp import RokuConnectionError, RokuConnectionTimeoutError, RokuError from rokuecp import RokuConnectionError, RokuConnectionTimeoutError, RokuError
@ -12,11 +12,10 @@ from homeassistant.exceptions import HomeAssistantError
from .entity import RokuEntity from .entity import RokuEntity
_RokuEntityT = TypeVar("_RokuEntityT", bound=RokuEntity) type _FuncType[_T, **_P] = Callable[Concatenate[_T, _P], Awaitable[Any]]
_P = ParamSpec("_P") type _ReturnFuncType[_T, **_P] = Callable[
Concatenate[_T, _P], Coroutine[Any, Any, None]
_FuncType = Callable[Concatenate[_RokuEntityT, _P], Awaitable[Any]] ]
_ReturnFuncType = Callable[Concatenate[_RokuEntityT, _P], Coroutine[Any, Any, None]]
def format_channel_name(channel_number: str, channel_name: str | None = None) -> str: def format_channel_name(channel_number: str, channel_name: str | None = None) -> str:
@ -27,7 +26,7 @@ def format_channel_name(channel_number: str, channel_name: str | None = None) ->
return channel_number return channel_number
def roku_exception_handler( def roku_exception_handler[_RokuEntityT: RokuEntity, **_P](
ignore_timeout: bool = False, ignore_timeout: bool = False,
) -> Callable[[_FuncType[_RokuEntityT, _P]], _ReturnFuncType[_RokuEntityT, _P]]: ) -> Callable[[_FuncType[_RokuEntityT, _P]], _ReturnFuncType[_RokuEntityT, _P]]:
"""Decorate Roku calls to handle Roku exceptions.""" """Decorate Roku calls to handle Roku exceptions."""

View file

@ -4,7 +4,7 @@ from __future__ import annotations
from collections.abc import Callable from collections.abc import Callable
import logging import logging
from typing import TYPE_CHECKING, Any, Concatenate, ParamSpec, TypeVar, overload from typing import TYPE_CHECKING, Any, Concatenate, overload
from requests.exceptions import Timeout from requests.exceptions import Timeout
from soco import SoCo from soco import SoCo
@ -26,29 +26,26 @@ UID_POSTFIX = "01400"
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
_T = TypeVar( type _SonosEntitiesType = (
"_T", bound="SonosSpeaker | SonosMedia | SonosEntity | SonosHouseholdCoordinator" SonosSpeaker | SonosMedia | SonosEntity | SonosHouseholdCoordinator
) )
_R = TypeVar("_R") type _FuncType[_T, **_P, _R] = Callable[Concatenate[_T, _P], _R]
_P = ParamSpec("_P") type _ReturnFuncType[_T, **_P, _R] = Callable[Concatenate[_T, _P], _R | None]
_FuncType = Callable[Concatenate[_T, _P], _R]
_ReturnFuncType = Callable[Concatenate[_T, _P], _R | None]
@overload @overload
def soco_error( def soco_error[_T: _SonosEntitiesType, **_P, _R](
errorcodes: None = ..., errorcodes: None = ...,
) -> Callable[[_FuncType[_T, _P, _R]], _FuncType[_T, _P, _R]]: ... ) -> Callable[[_FuncType[_T, _P, _R]], _FuncType[_T, _P, _R]]: ...
@overload @overload
def soco_error( def soco_error[_T: _SonosEntitiesType, **_P, _R](
errorcodes: list[str], errorcodes: list[str],
) -> Callable[[_FuncType[_T, _P, _R]], _ReturnFuncType[_T, _P, _R]]: ... ) -> Callable[[_FuncType[_T, _P, _R]], _ReturnFuncType[_T, _P, _R]]: ...
def soco_error( def soco_error[_T: _SonosEntitiesType, **_P, _R](
errorcodes: list[str] | None = None, errorcodes: list[str] | None = None,
) -> Callable[[_FuncType[_T, _P, _R]], _ReturnFuncType[_T, _P, _R]]: ) -> Callable[[_FuncType[_T, _P, _R]], _ReturnFuncType[_T, _P, _R]]:
"""Filter out specified UPnP errors and raise exceptions for service calls.""" """Filter out specified UPnP errors and raise exceptions for service calls."""

View file

@ -7,7 +7,7 @@ import contextlib
from enum import Enum from enum import Enum
import functools import functools
import logging import logging
from typing import TYPE_CHECKING, Any, ParamSpec, TypedDict from typing import TYPE_CHECKING, Any, TypedDict
import zigpy.exceptions import zigpy.exceptions
import zigpy.util import zigpy.util
@ -51,10 +51,8 @@ _LOGGER = logging.getLogger(__name__)
RETRYABLE_REQUEST_DECORATOR = zigpy.util.retryable_request(tries=3) RETRYABLE_REQUEST_DECORATOR = zigpy.util.retryable_request(tries=3)
UNPROXIED_CLUSTER_METHODS = {"general_command"} UNPROXIED_CLUSTER_METHODS = {"general_command"}
type _FuncType[**_P] = Callable[_P, Awaitable[Any]]
_P = ParamSpec("_P") type _ReturnFuncType[**_P] = Callable[_P, Coroutine[Any, Any, Any]]
_FuncType = Callable[_P, Awaitable[Any]]
_ReturnFuncType = Callable[_P, Coroutine[Any, Any, Any]]
@contextlib.contextmanager @contextlib.contextmanager
@ -75,7 +73,7 @@ def wrap_zigpy_exceptions() -> Iterator[None]:
raise HomeAssistantError(message) from exc raise HomeAssistantError(message) from exc
def retry_request(func: _FuncType[_P]) -> _ReturnFuncType[_P]: def retry_request[**_P](func: _FuncType[_P]) -> _ReturnFuncType[_P]:
"""Send a request with retries and wrap expected zigpy exceptions.""" """Send a request with retries and wrap expected zigpy exceptions."""
@functools.wraps(func) @functools.wraps(func)

View file

@ -5,26 +5,26 @@ from __future__ import annotations
import asyncio import asyncio
from collections.abc import Callable from collections.abc import Callable
import functools import functools
from typing import Any, TypeVar, cast, overload from typing import Any, cast, overload
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
from homeassistant.util.hass_dict import HassKey from homeassistant.util.hass_dict import HassKey
_T = TypeVar("_T") type _FuncType[_T] = Callable[[HomeAssistant], _T]
_FuncType = Callable[[HomeAssistant], _T]
@overload @overload
def singleton(data_key: HassKey[_T]) -> Callable[[_FuncType[_T]], _FuncType[_T]]: ... def singleton[_T](
data_key: HassKey[_T],
) -> Callable[[_FuncType[_T]], _FuncType[_T]]: ...
@overload @overload
def singleton(data_key: str) -> Callable[[_FuncType[_T]], _FuncType[_T]]: ... def singleton[_T](data_key: str) -> Callable[[_FuncType[_T]], _FuncType[_T]]: ...
def singleton(data_key: Any) -> Callable[[_FuncType[_T]], _FuncType[_T]]: def singleton[_T](data_key: Any) -> Callable[[_FuncType[_T]], _FuncType[_T]]:
"""Decorate a function that should be called once per instance. """Decorate a function that should be called once per instance.
Result will be cached and simultaneous calls will be handled. Result will be cached and simultaneous calls will be handled.