pytype
pytype copied to clipboard
Type narrowing does not narrow the type of `__class__`
Consider the following example:
from typing import TypeVar
T = TypeVar("T")
def test(obj: T | None) -> type[T]:
if obj is None:
raise TypeError
return obj.__class__
test(123)
This produces an unexpected error:
$ pytype typevar_narrow2.py
File "/home/eltoder/dev/scratch/typevar_narrow2.py", line 8, in test: bad option 'Type[None]' in return type [bad-return-type]
Expected: Type[int]
Actually returned: Type[Optional[int]]
Even though pytype knows that the type of obj after the if is just int and not Optional[int] (confirmed by adding reveal_type), it still thinks that the type of obj.__class__ is Type[Optional[int]]. However, pytype works as expected if I replace obj.__class__ with type(obj). A similar case can be constructed by using a bounded TypeVar:
from typing import TypeVar
T = TypeVar("T", bound=int)
def test(obj: T | None) -> type[T]:
if obj is None:
raise TypeError
return obj.__class__
This one does not need a call to test.
Both examples work as expected in mypy.
Actually, this does not need TypeVars:
def test(obj: int | None) -> type[int]:
if obj is None:
return int
return obj.__class__
produces
$ pytype class_narrow.py
...
File "/home/eltoder/dev/scratch/class_narrow.py", line 4, in test: bad option 'Type[None]' in return type [bad-return-type]
Expected: Type[int]
Actually returned: Type[Optional[int]]
But using type(obj) works.