-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Closed
Labels
bugmypy got something wrongmypy got something wrongtopic-typeguard-typeisTypeGuard / TypeIs / PEP 647 / PEP 742TypeGuard / TypeIs / PEP 647 / PEP 742
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.valueattribute. - The
LeftOrRightis aUnionof those types. xis a variable of typeLeftOrRight[str, int]. In this example it has valueLeft("")- Using
isinstance()works fine to figure out whetherxis eitherLeftorRight, and within theif/elseblock the types are correct, including the typesLandR(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.
MicaelJarniac, DetachHead, KotlinIsland, lucascust2 and Fulguritude
Metadata
Metadata
Assignees
Labels
bugmypy got something wrongmypy got something wrongtopic-typeguard-typeisTypeGuard / TypeIs / PEP 647 / PEP 742TypeGuard / TypeIs / PEP 647 / PEP 742