Improve logging util typing (#105968)

This commit is contained in:
Marc Mueller 2023-12-18 14:54:12 +01:00 committed by GitHub
parent 58070e14a7
commit b671de8942
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -9,11 +9,12 @@ import logging
import logging.handlers import logging.handlers
import queue import queue
import traceback import traceback
from typing import Any, TypeVar, cast, overload from typing import Any, TypeVar, TypeVarTuple, cast, overload
from homeassistant.core import HomeAssistant, callback, is_callback from homeassistant.core import HomeAssistant, callback, is_callback
_T = TypeVar("_T") _T = TypeVar("_T")
_Ts = TypeVarTuple("_Ts")
class HomeAssistantQueueHandler(logging.handlers.QueueHandler): class HomeAssistantQueueHandler(logging.handlers.QueueHandler):
@ -83,7 +84,7 @@ def async_activate_log_queue_handler(hass: HomeAssistant) -> None:
listener.start() listener.start()
def log_exception(format_err: Callable[..., Any], *args: Any) -> None: def log_exception(format_err: Callable[[*_Ts], Any], *args: *_Ts) -> None:
"""Log an exception with additional context.""" """Log an exception with additional context."""
module = inspect.getmodule(inspect.stack(context=0)[1].frame) module = inspect.getmodule(inspect.stack(context=0)[1].frame)
if module is not None: if module is not None:
@ -102,9 +103,9 @@ def log_exception(format_err: Callable[..., Any], *args: Any) -> None:
async def _async_wrapper( async def _async_wrapper(
async_func: Callable[..., Coroutine[Any, Any, None]], async_func: Callable[[*_Ts], Coroutine[Any, Any, None]],
format_err: Callable[..., Any], format_err: Callable[[*_Ts], Any],
*args: Any, *args: *_Ts,
) -> None: ) -> None:
"""Catch and log exception.""" """Catch and log exception."""
try: try:
@ -114,7 +115,7 @@ async def _async_wrapper(
def _sync_wrapper( def _sync_wrapper(
func: Callable[..., Any], format_err: Callable[..., Any], *args: Any func: Callable[[*_Ts], Any], format_err: Callable[[*_Ts], Any], *args: *_Ts
) -> None: ) -> None:
"""Catch and log exception.""" """Catch and log exception."""
try: try:
@ -125,7 +126,7 @@ def _sync_wrapper(
@callback @callback
def _callback_wrapper( def _callback_wrapper(
func: Callable[..., Any], format_err: Callable[..., Any], *args: Any func: Callable[[*_Ts], Any], format_err: Callable[[*_Ts], Any], *args: *_Ts
) -> None: ) -> None:
"""Catch and log exception.""" """Catch and log exception."""
try: try:
@ -136,21 +137,21 @@ def _callback_wrapper(
@overload @overload
def catch_log_exception( def catch_log_exception(
func: Callable[..., Coroutine[Any, Any, Any]], format_err: Callable[..., Any] func: Callable[[*_Ts], Coroutine[Any, Any, Any]], format_err: Callable[[*_Ts], Any]
) -> Callable[..., Coroutine[Any, Any, None]]: ) -> Callable[[*_Ts], Coroutine[Any, Any, None]]:
... ...
@overload @overload
def catch_log_exception( def catch_log_exception(
func: Callable[..., Any], format_err: Callable[..., Any] func: Callable[[*_Ts], Any], format_err: Callable[[*_Ts], Any]
) -> Callable[..., None] | Callable[..., Coroutine[Any, Any, None]]: ) -> Callable[[*_Ts], None] | Callable[[*_Ts], Coroutine[Any, Any, None]]:
... ...
def catch_log_exception( def catch_log_exception(
func: Callable[..., Any], format_err: Callable[..., Any] func: Callable[[*_Ts], Any], format_err: Callable[[*_Ts], Any]
) -> Callable[..., None] | Callable[..., Coroutine[Any, Any, None]]: ) -> Callable[[*_Ts], None] | Callable[[*_Ts], Coroutine[Any, Any, None]]:
"""Decorate a function func to catch and log exceptions. """Decorate a function func to catch and log exceptions.
If func is a coroutine function, a coroutine function will be returned. If func is a coroutine function, a coroutine function will be returned.
@ -159,24 +160,24 @@ def catch_log_exception(
# Check for partials to properly determine if coroutine function # Check for partials to properly determine if coroutine function
check_func = func check_func = func
while isinstance(check_func, partial): while isinstance(check_func, partial):
check_func = check_func.func check_func = check_func.func # type: ignore[unreachable] # false positive
if asyncio.iscoroutinefunction(check_func): if asyncio.iscoroutinefunction(check_func):
async_func = cast(Callable[..., Coroutine[Any, Any, None]], func) async_func = cast(Callable[[*_Ts], Coroutine[Any, Any, None]], func)
return wraps(async_func)(partial(_async_wrapper, async_func, format_err)) return wraps(async_func)(partial(_async_wrapper, async_func, format_err)) # type: ignore[return-value]
if is_callback(check_func): if is_callback(check_func):
return wraps(func)(partial(_callback_wrapper, func, format_err)) return wraps(func)(partial(_callback_wrapper, func, format_err)) # type: ignore[return-value]
return wraps(func)(partial(_sync_wrapper, func, format_err)) return wraps(func)(partial(_sync_wrapper, func, format_err)) # type: ignore[return-value]
def catch_log_coro_exception( def catch_log_coro_exception(
target: Coroutine[Any, Any, _T], format_err: Callable[..., Any], *args: Any target: Coroutine[Any, Any, _T], format_err: Callable[[*_Ts], Any], *args: *_Ts
) -> Coroutine[Any, Any, _T | None]: ) -> Coroutine[Any, Any, _T | None]:
"""Decorate a coroutine to catch and log exceptions.""" """Decorate a coroutine to catch and log exceptions."""
async def coro_wrapper(*args: Any) -> _T | None: async def coro_wrapper(*args: *_Ts) -> _T | None:
"""Catch and log exception.""" """Catch and log exception."""
try: try:
return await target return await target