python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.22k stars 2.78k forks source link

isinstance(x, Type) not accepted #3060

Open JukkaL opened 7 years ago

JukkaL commented 7 years ago

isinstance(x, Type) generates in an error, even though it should probably be considered equivalent to isinstance(x, type). Example:

from typing import Type

def f(x: Type[int]) -> None:
    if isinstance(x, Type):  # Argument 2 to "isinstance" has incompatible type "object"; 
                             # expected "Union[type, Tuple[Union[type, Tuple[Any, ...]], ...]]"
        pass
pkch commented 7 years ago

I almost fixed it inside #3070, but then I realized that the required change to typeshed (from Union[type, Tuple[Union[type, Tuple[Any, ...]], ...]] to Union[object, Tuple[Union[object, Tuple[Any, ...]], ...]]) effectively eliminates type checking of the 2nd argument to isinstance. That would be quite disappointing.

What else can we do?

Map Type to be something other than object during type inference? Perhaps a special singleton class TypeObject?

gvanrossum commented 7 years ago

Yeah, that would be equivalent to making the type object. But there's special-casing for isinstance() calls in mypy -- maybe we can expand that to manually check that the recursive tuple is valid? Or maybe we can implement recursive type aliases, at last (#731).

pkch commented 7 years ago

I guess a narrow fix could be to redefine Type in typing.pyi as class Type: ... instead of Type = object(). This would pass the type check for isinstance(x, Type).

We would still have to add some code elsewhere to make @JukkaL example pass, since at present Type[int] is not recognized as a subtype of Type, so mypy thinks that everything after isinstance(x, Type) is unreachable.

gvanrossum commented 7 years ago

Is this about mypy or runtime? Making the behaviors of isinstance()/issubclass() match between static checks and runtime can be tricky.

pkch commented 7 years ago

I think mypy. It seems Python runtime returns True on isinstance(c, Type) whenever c is of type type. This is precisely what mypy should do as well (of course, assuming it can statically infer that c of type type).

ilevkivskyi commented 5 years ago

On current master the error is even worse:

Argument 2 to "isinstance" has incompatible type "_SpecialForm";
expected "Union[type, Tuple[Union[type, Tuple[Any, ...]], ...]]"