mypy icon indicating copy to clipboard operation
mypy copied to clipboard

Adding a field to a callback protocol changes the checks performed by mypy

Open vxgmichel opened this issue 1 year ago • 0 comments

I noticed something really weird about callback protocols. Consider the following example:

from typing import TypeVar, Protocol


T = TypeVar("T")


class MyCallable(Protocol[T]):
    __name__: str

    def __call__(
        self,
        __arg: T,
    ) -> T: ...


def decorator(x: MyCallable[T]) -> MyCallable[T]:
    return x


@decorator
def func(arg: T) -> T:
    return arg


x = func(1)

It works fine with mypy 1.10.0 (although it fails to check with pyright 1.1.360: https://github.com/microsoft/pyright/issues/7782).

However, adding a __name__: str field to the protocol changes the checks performed by mypy. The example becomes:

from typing import TypeVar, Protocol


T = TypeVar("T")


class MyCallable(Protocol[T]):
    __name__: str

    def __call__(
        self,
        __arg: T,
    ) -> T: ...


def decorator(x: MyCallable[T]) -> MyCallable[T]:
    return x


@decorator
def func(arg: T) -> T:
    return arg


x = func(1)

And it fails with:

test.py:25: error: Need type annotation for "x"  [var-annotated]
test.py:25: error: Argument 1 to "__call__" of "MyCallable" has incompatible type "int"; expected Never  [arg-type]

vxgmichel avatar Apr 26 '24 18:04 vxgmichel