-
Here is a contrived code example: from typing import Any, Callable, Dict
from typing_extensions import Concatenate, ParamSpec
from functools import wraps
P = ParamSpec("P")
PreWrapFunc = Callable[Concatenate[Dict[str, str], P], str]
PostWrapFunc = Callable[P, str]
# Ignore the below for now, as the type aliases above are what is failing
def second_order_decorator(mappings: Dict[str, str]) -> Callable[[PreWrapFunc], PostWrapFunc]:
def decorator(func: PreWrapFunc) -> PostWrapFunc:
@wraps(func)
def wrapped_func(*args: Any, **kwargs: Any):
return func(mappings, *args, **kwargs)
return wrapped_func
return decorator
@second_order_decorator(mappings={"a": "1", "b": "2"})
def decorated_func(mappings: Dict[str, str], a: int, b: str) -> str:
return "|".join(k + ":" + v for k, v in mappings.items()) + str(a) + b Here is the output from MyPy:
It's not clear to me what is wrong with my type aliases. The I ran the above code in pyright and it produced no errors. Further, if I manipulate the parameters of
|
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Yes, this is a bug in mypy. Your code has some issues with the type annotations, but even when I fix those errors, mypy still generates errors. Mypy's support for PEP 612 is pretty new, so it's not surprising that it still has some bugs. The problem in your code becomes evident if you turn on strict type checking in pyright (i.e. add Here's the code with corrected type annotations. Note that it also uses # pyright: strict
from typing import Callable, Dict
from typing_extensions import Concatenate, ParamSpec
from functools import wraps
P = ParamSpec("P")
PreWrapFunc = Callable[Concatenate[Dict[str, str], P], str]
PostWrapFunc = Callable[P, str]
def second_order_decorator(mappings: Dict[str, str]) -> Callable[[PreWrapFunc[P]], PostWrapFunc[P]]:
def decorator(func: PreWrapFunc[P]) -> PostWrapFunc[P]:
@wraps(func)
def wrapped_func(*args: P.args, **kwargs: P.kwargs):
return func(mappings, *args, **kwargs)
return wrapped_func
return decorator
@second_order_decorator(mappings={"a": "1", "b": "2"})
def decorated_func(mappings: Dict[str, str], a: int, b: str) -> str:
return "|".join(k + ":" + v for k, v in mappings.items()) + str(a) + b |
Beta Was this translation helpful? Give feedback.
Yes, this is a bug in mypy. Your code has some issues with the type annotations, but even when I fix those errors, mypy still generates errors. Mypy's support for PEP 612 is pretty new, so it's not surprising that it still has some bugs.
The problem in your code becomes evident if you turn on strict type checking in pyright (i.e. add
# pyright: strict
anywhere in the file). You have defined two generic type aliases calledPreWrapFunc
andPostWrapFunc
. These type aliases each take a single type argument which must be compatible with a ParamSpec type parameter. But when you use these type aliases further down in the code, you are not providing a type argument. That means a type checker will…