-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Description
I think there are a few problems with isinstance inference.
- This code type checks with
mypy --strcit --python-version 3.6, but it should not:
from typing import *
def f(x: Union[int, str], typ: type) -> None:
if isinstance(x, (typ, int)):
print(x + 1)
The semantic analyzer concludes that within the body of if isinstance(), the type of x must be int. It's not, however. For example, in this case f('a', str), the if branch will be followed even though x is not an int (and this will cause runtime TypeError without any mypy warnings).
The reason this happens is that type annotation is represented as an Instance rather than as a FunctionLike inside checker.py:get_isinstance_type(). As a result, it's skipped entirely in the loop, and only int is added to types, so sem analyzer thinks x must absolutely be int.
One solution is to make type represented with an instance of CallableType (why isn't it btw?!). Another solution is to simply add a bit of logic to the loop to properly handle this case.
- This code:
def f(x: Union[int, str, List, Tuple]) -> None:
if isinstance(x, (str, (list, tuple))):
print(x[1])
results in error: Argument 2 to "isinstance" has incompatible type "Tuple[str, Tuple[List[_T], Tuple[_T_co, ...]]]"; expected "Union[type, Tuple[type, ...]]".
This is because there's this weird thing in python that allows to put nested tuples as the second argument to isinstance, and mypy (along with most other people) doesn't know about it. I don't know if it's worth fixing, but it's super easy (just flatten the second argument if it's a tuple).
If my understanding is correct, I'll make a PR.