mypy icon indicating copy to clipboard operation
mypy copied to clipboard

`Arg(T, 'name')` not equivalent to `T` in `Callable`

Open matteosantama opened this issue 3 years ago • 2 comments

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

matteosantama avatar Aug 15 '22 20:08 matteosantama

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?)

A5rocks avatar Sep 13 '22 03:09 A5rocks