From 8f3478a08af9efb80d836fc9b88987d744a3e170 Mon Sep 17 00:00:00 2001 From: Piotr Kopalko Date: Sat, 19 Aug 2023 00:05:27 +0200 Subject: [PATCH] feat: Use ParamsSpec to type deprecated decorator --- falcon/util/deprecation.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/falcon/util/deprecation.py b/falcon/util/deprecation.py index 5e2607ad7..10b4cd45b 100644 --- a/falcon/util/deprecation.py +++ b/falcon/util/deprecation.py @@ -21,6 +21,12 @@ from typing import Any from typing import Callable from typing import Optional +from typing import TypeVar + +try: + from typing import ParamSpec +except ImportError: # pragma: no cover + from typing_extensions import ParamSpec # type: ignore import warnings @@ -44,9 +50,13 @@ class DeprecatedWarning(UserWarning): pass +Wrapped = TypeVar('Wrapped') +Params = ParamSpec('Params') + + def deprecated( instructions: str, is_property: bool = False, method_name: Optional[str] = None -) -> Callable[[Callable[..., Any]], Any]: +) -> Callable[[Callable[Params, Any]], Any]: """Flag a method as deprecated. This function returns a decorator which can be used to mark deprecated @@ -65,7 +75,7 @@ def deprecated( """ - def decorator(func: Callable[..., Any]) -> Callable[[Callable[..., Any]], Any]: + def decorator(func: Callable[Params, Any]) -> Callable[Params, Any]: object_name = 'property' if is_property else 'function' post_name = '' if is_property else '(...)' @@ -74,7 +84,9 @@ def decorator(func: Callable[..., Any]) -> Callable[[Callable[..., Any]], Any]: ) @functools.wraps(func) - def wrapper(*args: Any, **kwargs: Any) -> Callable[..., Any]: + def wrapper( + *args: Params.args, **kwargs: Params.kwargs + ) -> Callable[Params, Any]: warnings.warn(message, category=DeprecatedWarning, stacklevel=2) return func(*args, **kwargs)