Description
Consider this code (playground)
from typing import Callable, ParamSpec, TypeVar
_ParamsT = ParamSpec("_ParamsT")
_T = TypeVar("_T")
def smoke_testable(*args: _ParamsT.args, **kwargs: _ParamsT.kwargs) -> Callable[[Callable[_ParamsT, _T]], type[_T]]:
assert args == (), args
def decorator(cls: Callable[_ParamsT, _T]) -> type[_T]:
assert isinstance(cls, type), type(cls)
cls._smoke_testable_kwargs = kwargs
return cls
return decorator
@smoke_testable(name="bob", size=512, flt=0.5) # Argument 1 has incompatible type "type[SomeClass]"; expected "Callable[[str, int, float], SomeClass]"
# @smoke_testable(size=512, name="bob", flt=0.5) # OK
# @smoke_testable(name=512, size="bob", flt=0.5) # Argument 1 has incompatible type "type[SomeClass]"; expected "Callable[[int, str, float], SomeClass]"
class SomeClass:
def __init__(self, size: int, name: str, flt: float) -> None:
pass
Mypy gives this error message for the decorator line (which has correct kwargs, but in an order different from __init__
):
Argument 1 has incompatible type "type[SomeClass]"; expected "Callable[[str, int, float], SomeClass]" [arg-type]
This seems clearly wrong; all the arguments to smoke_testable
were kwargs, and their order should not matter. If I change the order in smoke_testable to the same as __init__
, there is no error (line 2).
The third line should give an error (because it assigns an int to a str kwarg and a str to an int kwarg), and it does. However, the error message is surprising:
Argument 1 has incompatible type "type[SomeClass]"; expected "Callable[[int, str, float], SomeClass]"
As far as I can tell, the class is a Callable[[int, str, float], SomeClass]
.
Expected Behavior
The first decorator line should produce no error (it currently does).
The second decorator line should produce no error, and it currently does not.
The third decorator line should produce an error, but the error message should not claim that SomeClass
is not Callable[[int, str, float], SomeClass]
.
Your Environment
- Mypy version used: 1.6.1
- Mypy command-line flags: --strict
- Python version used: 3.11