Closed
Description
Bug Report
It seems the typing.TypeGuard
support is not able to properly discriminate a union of two (generic) types.
To Reproduce
- The example below defines two completely distinct types,
Left[L]
andRight[R]
, both of which happen to be generic and have a.value
attribute. - The
LeftOrRight
is aUnion
of those types. x
is a variable of typeLeftOrRight[str, int]
. In this example it has valueLeft("")
- Using
isinstance()
works fine to figure out whetherx
is eitherLeft
orRight
, and within theif/else
block the types are correct, including the typesL
andR
(bothTypeVar
) - The
is_left()
andis_right()
helpers usetyping.TypeGuard
, but Mypy does not recognize the types like it did with theisinstance()
check.
from typing import Generic, TypeGuard, TypeVar, Union
L = TypeVar("L")
R = TypeVar("R")
class Left(Generic[L]):
value: L
def __init__(self, value: L):
self.value = value
class Right(Generic[R]):
value: R
def __init__(self, value: R):
self.value = value
LeftOrRight = Union[Left[L], Right[R]]
def is_left(obj: LeftOrRight[L, R]) -> TypeGuard[Left[L]]:
return isinstance(obj, Left)
def is_right(obj: LeftOrRight[L, R]) -> TypeGuard[Right[R]]:
return isinstance(obj, Right)
x: LeftOrRight[str, int] = Left("")
reveal_type(x) # Revealed type is "Union[Left[builtins.str], Right[builtins.int]]"
if isinstance(x, Left):
reveal_type(x) # Revealed type is "Left[builtins.str]"
x.value + "" # only valid for str
else:
reveal_type(x) # Revealed type is "Right[builtins.int]"
x.value + 10 # only valid for int
if is_left(x):
reveal_type(x) # Revealed type is "Left[L`-1]"
x.value + "" # Unsupported left operand type for + ("L") [operator]
else:
reveal_type(x) # Revealed type is "Union[Left[builtins.str], Right[builtins.int]]"
x.value + 10 # Unsupported operand types for + ("str" and "int") [operator]
Expected Behavior
is_left()
and is_right()
act as type-safe ways to discriminate between the two members of the Union
, including the actual type of the (generic) .value
attribute.
Actual Behavior
reveal_type()
returns wrong results- type errors reported in what seems to be perfectly fine and very strict code
Your Environment
This happens with both Mypy 0.910 (current release as time of writing) and today's git
checkout of the main branch.