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
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?
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).
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.
Is this about mypy or runtime? Making the behaviors of isinstance()/issubclass() match between static checks and runtime can be tricky.
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).
On current master the error is even worse:
Argument 2 to "isinstance" has incompatible type "_SpecialForm";
expected "Union[type, Tuple[Union[type, Tuple[Any, ...]], ...]]"
Most helpful comment
On current master the error is even worse: