mypy
mypy copied to clipboard
`Arg(T, 'name')` not equivalent to `T` in `Callable`
Given the code
T = TypeVar("T", bound="Foo")
P = ParamSpec("P")
# this class serves as a decorator
class print_y_first:
def __call__(
self, method: Callable[Concatenate[T, P], str]
) -> Callable[Concatenate[T, P], str]:
def wrapper(_self: T, *args: P.args, **kwargs: P.kwargs) -> str:
print(_self.y)
return method(*args, **kwargs)
return wrapper
class Foo:
y: int
@print_y_first()
def stringify(self, x: int) -> str:
return str(x)
Mypy reports
error: Incompatible return value type (got "Callable[[Arg(T, '_self'), **P], str]", expected "Callable[[T, **P], str]") [return-value]
note: This may be because "wrapper" has arguments named: "_self"
It does not recognize that
Callable[[Arg(T, '_self'), **P], str] == Callable[[T, **P], str]
Mypy version: mypy 0.971 (compiled: yes)
Mypy config options: --strict=True
Python version: 3.10.4
Heya! This was a bit confusing while I was implementing Concatenate which is why I added that note -- it doesn't seem to be helping so I may have to reconsider wording...
But AFAICT, this is because:
@print_y_first()
def blah(self: str, _self: int) -> str:
return str(_self)
Now, blah("m", _self=42) would be accepted if blah were a Callable[[str, _self: int], str]... But you can probably see the unsafety here :P
The solution is either to stick a / after _self in the decorator, or --no-strict-concatenate (I think that was the flag?)