diff --git a/appdaemon/entity.py b/appdaemon/entity.py index 4aad22c68..29f5859cd 100644 --- a/appdaemon/entity.py +++ b/appdaemon/entity.py @@ -103,7 +103,7 @@ async def set_state(self, **kwargs: Optional[Any]) -> dict: @utils.sync_wrapper async def get_state( - self, attribute: str = None, default: Any = None, copy: bool = True, **kwargs: Optional[Any] + self, attribute: str | None = None, default: Any = None, copy: bool = True, **kwargs: Optional[Any] ) -> Any: """Gets the state of any entity within AD. @@ -280,7 +280,7 @@ async def listen_state(self, callback: Callable, **kwargs: Optional[Any]) -> str return await self.AD.state.add_state_callback(name, namespace, entity_id, callback, kwargs) @utils.sync_wrapper - async def add(self, state: Union[str, int, float] = None, attributes: dict = None) -> None: + async def add(self, state: Union[str, int, float] | None = None, attributes: dict | None = None) -> None: """Adds a non-existent entity, by creating it within a namespaces. It should be noted that this api call, is mainly for creating AD internal entities. @@ -369,9 +369,9 @@ async def call_service(self, service: str, **kwargs: Optional[Any]) -> Any: async def wait_state( self, state: Any, - attribute: Union[str, int] = None, + attribute: Union[str, int] | None = None, duration: Union[int, float] = 0, - timeout: Union[int, float] = None, + timeout: Union[int, float] | None = None, ) -> None: """Used to wait for the state of an entity's attribute diff --git a/appdaemon/utils.py b/appdaemon/utils.py index 3496b3164..f5e859f15 100644 --- a/appdaemon/utils.py +++ b/appdaemon/utils.py @@ -20,7 +20,7 @@ from datetime import timedelta from functools import wraps from types import ModuleType -from typing import Any, Callable, Dict +from typing import Any, Callable, Dict, ParamSpec, TypeVar import dateutil.parser import tomli @@ -215,7 +215,15 @@ def check_state(logger, new_state, callback_state, name) -> bool: return passed -def sync_wrapper(coro) -> Callable: +T = ParamSpec("T") # Arguments to the function +# Get return type inferred by pyright to be `Unknown` by using this only as return type (but not as argument). +# This enables to benefit from the `reportUnknownParameterType` lint and similar other unknown-related lints. +MakeReturnTypeUnknown = TypeVar("MakeReturnTypeUnknown") + + +def sync_wrapper( + coro: Callable[T, Any] +) -> Callable[T, MakeReturnTypeUnknown]: # pyright: ignore[reportInvalidTypeVarUse] @wraps(coro) def inner_sync_wrapper(self, *args, **kwargs): is_async = None @@ -229,14 +237,14 @@ def inner_sync_wrapper(self, *args, **kwargs): if is_async is True: # don't use create_task. It's python3.7 only - f = asyncio.ensure_future(coro(self, *args, **kwargs)) + f = asyncio.ensure_future(coro(self, *args, **kwargs)) # type: ignore self.AD.futures.add_future(self.name, f) else: - f = run_coroutine_threadsafe(self, coro(self, *args, **kwargs)) + f = run_coroutine_threadsafe(self, coro(self, *args, **kwargs)) # type: ignore return f - return inner_sync_wrapper + return inner_sync_wrapper # pyright: ignore[reportReturnType] def _timeit(func):