Mypy Errors For Decorator W/ Arguments
Solution 1:
The issue here is the return type of the outer layer of your decorator. You need to correct your type annotation to the following:
from time import sleep
from typing import TypeVar, Any, Callable, castF= TypeVar('F', bound=Callable[..., Any])
def multi_try_if_error(n_tries: int, sleep_duration: int) -> Callable[[F], F]:
def decorator(fn: F) -> F:
def wrapper(*args: Any, **kwargs: Any) -> Any:
for _ in range(n_tries):
try:
return fn(*args, **kwargs)
except Exception as e:
caught = e
sleep(sleep_duration)
raise ValueError(caught)return cast(F, wrapper)
return decorator
@multi_try_if_error(n_tries=3, sleep_duration=1)
def query_db(q: str) -> None:
return
What's going on here
Conceptualising (and type-hinting) a simple decorator that doesn't take arguments is fairly straighforward. We define a function C
that takes in a function of type F
and spits out a new function that is also of type F
.
# Decorator that doesn't take arguments takes in a function,# and spits out a function of the same typeDecoratorTypeNoArgs = Callable[[F], F]
It's important to recognise, however, that that's not what a decorator that takes arguments is doing. Rather than taking in a function of type F
and spitting out a new function of type F
(which can be conceptualised as Callable[[F], F]
), multi_try_if_error
is a function that takes in two int
arguments and returns a function that will take in a function of type F
and return a function of type F
(which can be conceptualised as Callable[[int, int], Callable[[F], F]]
).
# Decorator that takes arguments takes in arguments,# and spits out a decorator that doesn't take arguments
DecoratorTypeWithArgs = Callable[[int, int], Callable[[F], F]]
As such, the outer layer of your decorator must be annotated as returning Callable[[F], F]
rather than as returning F
. Once you make this change, your decorator passes MyPy --strict with flying colours.
Post a Comment for "Mypy Errors For Decorator W/ Arguments"