-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
Bug Report
Attempting to make a type alias for a decorator results in MyPy losing type information.
To Reproduce
from typing import *
type Fn[**P, R] = Callable[P, R]
type Decorator[**P, R] = Callable[[Fn[P, R]], Fn[P, R]]
def do_the_thing[**P, R]() -> Decorator[P, R]:
def decorator(fn: Fn[P, R]) -> Fn[P, R]:
return fn
return decorator
@do_the_thing()
def blahblah() -> None:
pass
Seems this is not an artifact of how variance is being calculated with the new type alias syntax as using the old style syntax has the same issue when declaring the type hints...
from typing import *
P = ParamSpec("P")
R_co = TypeVar("R_co", covariant=True)
Fn: TypeAlias = Callable[P, R_co]
Decorator: TypeAlias = Callable[[Fn[P, R_co]], Fn[P, R_co]]
def do_the_thing[**P, R_co]() -> Decorator[P, R_co]:
def decorator(fn: Fn[P, R_co]) -> Fn[P, R_co]:
return fn
return decorator
@do_the_thing()
def blahblah() -> None:
pass
...and the same issue if I just discard the type variables entirely in the function definition:
from typing import *
P = ParamSpec("P")
R_co = TypeVar("R_co", covariant=True)
Fn: TypeAlias = Callable[P, R_co]
Decorator: TypeAlias = Callable[[Fn[P, R_co]], Fn[P, R_co]]
def do_the_thing() -> Decorator[P, R_co]:
def decorator(fn: Fn[P, R_co]) -> Fn[P, R_co]:
return fn
return decorator
@do_the_thing()
def blahblah() -> None:
pass
Using a protocol doesn't work either:
from typing import *
type Fn[**P, R] = Callable[P, R]
class Decorator[**P, R](Protocol):
def __call__(self, fn: Fn[P, R], /) -> Fn[P, R]: ...
def do_the_thing[**P, R]() -> Decorator[P, R]:
def decorator(fn: Fn[P, R]) -> Fn[P, R]:
return fn
return decorator
@do_the_thing()
def blahblah() -> None:
pass
...so it seems the type information is just totally discarded.
Strangely, if I don't type-alias the decorator, then it works fine (which is a workaround, but very annoying and verbose for more complicated logic).
# this is fine.
def do_the_thing[**P, R]() -> Callable[[Fn[P, R]], Fn[P, R]]:
def decorator(fn: Fn[P, R]) -> Fn[P, R]:
return fn
return decorator
The problem is that I want to be able to alias Callable[[Fn[P, R]], Fn[P, R]]
to a clean single identifier that I can reuse in the current type context, but I cannot find a nice way of doing that at the moment.
Expected Behavior
This should be valid.
Actual Behavior
main.py:14: error: Argument 1 has incompatible type "Callable[[], None]"; expected "Callable[[VarArg(Never), KwArg(Never)], Never]" [arg-type]
Found 1 error in 1 file (checked 1 source file)
Related Issues:
I came across GH-16512, but that was closed as fixed. Not sure if it is the same problem or not!
Your Environment
- Mypy version used: 1.14.1, 1.15.0
- Mypy command-line flags: none
- Mypy configuration options from
mypy.ini
(and other config files): none - Python version used: 3.12, 3.13
- Reproducible in https://mypy-play.net/?mypy=1.15.0&python=3.13