Skip to content

Commit 9a1459d

Browse files
committed
test wip
1 parent c989ac5 commit 9a1459d

4 files changed

Lines changed: 294 additions & 39 deletions

File tree

test-data/unit/check-enum.test

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2743,3 +2743,191 @@ reveal_type(Wrapper.Nested.FOO) # N: Revealed type is "Literal[__main__.Wrapper
27432743
reveal_type(Wrapper.Nested.FOO.value) # N: Revealed type is "builtins.ellipsis"
27442744
reveal_type(Wrapper.Nested.FOO._value_) # N: Revealed type is "builtins.ellipsis"
27452745
[builtins fixtures/enum.pyi]
2746+
2747+
[case testStrEnumEqualityReachability]
2748+
# flags: --strict-equality --warn-unreachable
2749+
2750+
from __future__ import annotations
2751+
import enum
2752+
2753+
# https://github.com/python/mypy/issues/17162
2754+
2755+
class MyEnum(str, enum.Enum):
2756+
A = 'a'
2757+
2758+
class MyEnum2(enum.StrEnum):
2759+
A = 'a'
2760+
2761+
def f1():
2762+
if MyEnum.A == 'a':
2763+
1 + ''
2764+
2765+
if MyEnum2.A == 'a':
2766+
1 + ''
2767+
[builtins fixtures/primitives.pyi]
2768+
2769+
[case testStrEnumEqualityNarrowing]
2770+
# flags: --strict-equality --warn-unreachable
2771+
2772+
from __future__ import annotations
2773+
import enum
2774+
from typing import Literal
2775+
2776+
# https://github.com/python/mypy/issues/18029
2777+
2778+
class Foo(enum.StrEnum):
2779+
FOO = 'a'
2780+
2781+
# Behaviour here is not yet ideal
2782+
2783+
def f1(a: Foo | Literal['foo']) -> Foo:
2784+
if a == 'foo':
2785+
reveal_type(a) # N: Revealed type is "__main__.Foo | Literal['foo']"
2786+
return Foo.FOO
2787+
2788+
reveal_type(a) # N: Revealed type is "__main__.Foo | Literal['foo']"
2789+
return a # E: Incompatible return value type (got "Foo | Literal['foo']", expected "Foo")
2790+
[builtins fixtures/primitives.pyi]
2791+
2792+
[case testStrEnumEqualityAlias]
2793+
# flags: --strict-equality --warn-unreachable
2794+
# https://github.com/python/mypy/issues/16830
2795+
from __future__ import annotations
2796+
from enum import Enum, auto
2797+
2798+
# https://github.com/python/mypy/issues/16830
2799+
2800+
class TrafficLight(Enum):
2801+
RED = auto()
2802+
AMBER = auto()
2803+
GREEN = auto()
2804+
2805+
YELLOW = AMBER # alias
2806+
2807+
# Behaviour here is not yet ideal
2808+
2809+
def demo1(inst: TrafficLight) -> None:
2810+
if inst is TrafficLight.AMBER:
2811+
reveal_type(inst) # N: Revealed type is "Literal[__main__.TrafficLight.AMBER]"
2812+
else:
2813+
reveal_type(inst) # N: Revealed type is "Literal[__main__.TrafficLight.RED] | Literal[__main__.TrafficLight.GREEN] | Literal[__main__.TrafficLight.YELLOW]"
2814+
2815+
if inst == TrafficLight.AMBER:
2816+
reveal_type(inst) # N: Revealed type is "Literal[__main__.TrafficLight.AMBER]"
2817+
else:
2818+
reveal_type(inst) # N: Revealed type is "Literal[__main__.TrafficLight.RED] | Literal[__main__.TrafficLight.GREEN] | Literal[__main__.TrafficLight.YELLOW]"
2819+
2820+
def demo2() -> None:
2821+
if TrafficLight.AMBER is TrafficLight.YELLOW: # E: Non-overlapping identity check (left operand type: "Literal[TrafficLight.AMBER]", right operand type: "Literal[TrafficLight.YELLOW]")
2822+
1 + '' # E: Unsupported operand types for + ("int" and "str")
2823+
else:
2824+
1 + '' # E: Unsupported operand types for + ("int" and "str")
2825+
[builtins fixtures/primitives.pyi]
2826+
2827+
2828+
[case testEnumEqualityNarrowing]
2829+
# flags: --strict-equality --warn-unreachable
2830+
2831+
from __future__ import annotations
2832+
from typing import cast
2833+
from enum import Enum, StrEnum
2834+
2835+
# https://github.com/python/mypy/issues/16830
2836+
2837+
class E(Enum):
2838+
A = "a"
2839+
B = "b"
2840+
C = "c"
2841+
2842+
class Custom:
2843+
def __eq__(self, other: object) -> bool: return True
2844+
2845+
class SE(StrEnum):
2846+
A = "a"
2847+
B = "b"
2848+
C = "c"
2849+
2850+
# Behaviour here is not yet ideal
2851+
2852+
def f1(x: int | str | E):
2853+
if x == E.A:
2854+
reveal_type(x) # N: Revealed type is "Literal[__main__.E.A]"
2855+
else:
2856+
reveal_type(x) # N: Revealed type is "builtins.int | builtins.str | Literal[__main__.E.B] | Literal[__main__.E.C]"
2857+
2858+
if x in cast(list[E], []):
2859+
reveal_type(x) # N: Revealed type is "__main__.E"
2860+
else:
2861+
reveal_type(x) # N: Revealed type is "builtins.int | builtins.str | __main__.E"
2862+
2863+
if x == str():
2864+
reveal_type(x) # N: Revealed type is "builtins.str"
2865+
else:
2866+
reveal_type(x) # N: Revealed type is "builtins.int | builtins.str | __main__.E"
2867+
2868+
def f2(x: int | Custom | E):
2869+
if x == E.A:
2870+
reveal_type(x) # N: Revealed type is "__main__.Custom | Literal[__main__.E.A]"
2871+
else:
2872+
reveal_type(x) # N: Revealed type is "builtins.int | __main__.Custom | Literal[__main__.E.B] | Literal[__main__.E.C]"
2873+
2874+
if x in cast(list[E], []):
2875+
reveal_type(x) # N: Revealed type is "__main__.Custom | __main__.E"
2876+
else:
2877+
reveal_type(x) # N: Revealed type is "builtins.int | __main__.Custom | __main__.E"
2878+
2879+
if x == str():
2880+
reveal_type(x) # N: Revealed type is "__main__.Custom"
2881+
else:
2882+
reveal_type(x) # N: Revealed type is "builtins.int | __main__.Custom | __main__.E"
2883+
2884+
def f3(x: int | str | SE):
2885+
if x == SE.A:
2886+
reveal_type(x) # N: Revealed type is "builtins.int | builtins.str | __main__.SE"
2887+
else:
2888+
reveal_type(x) # N: Revealed type is "builtins.int | builtins.str | __main__.SE"
2889+
2890+
if x in cast(list[SE], []):
2891+
reveal_type(x) # N: Revealed type is "builtins.int | builtins.str | __main__.SE"
2892+
else:
2893+
reveal_type(x) # N: Revealed type is "builtins.int | builtins.str | __main__.SE"
2894+
2895+
if x == str():
2896+
reveal_type(x) # N: Revealed type is "builtins.int | builtins.str | __main__.SE"
2897+
else:
2898+
reveal_type(x) # N: Revealed type is "builtins.int | builtins.str | __main__.SE"
2899+
2900+
def f4(x: int | Custom | SE):
2901+
if x == SE.A:
2902+
reveal_type(x) # N: Revealed type is "__main__.Custom | Literal[__main__.SE.A]"
2903+
else:
2904+
reveal_type(x) # N: Revealed type is "builtins.int | __main__.Custom | Literal[__main__.SE.B] | Literal[__main__.SE.C]"
2905+
2906+
if x in cast(list[SE], []):
2907+
reveal_type(x) # N: Revealed type is "__main__.Custom | __main__.SE"
2908+
else:
2909+
reveal_type(x) # N: Revealed type is "builtins.int | __main__.Custom | __main__.SE"
2910+
2911+
if x == str():
2912+
reveal_type(x) # N: Revealed type is "__main__.Custom | __main__.SE"
2913+
else:
2914+
reveal_type(x) # N: Revealed type is "builtins.int | __main__.Custom | __main__.SE"
2915+
2916+
2917+
def f5(x: str | Custom | SE):
2918+
if x == SE.A:
2919+
reveal_type(x) # N: Revealed type is "Literal[__main__.SE.A] | __main__.Custom"
2920+
else:
2921+
reveal_type(x) # N: Revealed type is "builtins.str | __main__.Custom"
2922+
2923+
if x in cast(list[SE], []):
2924+
reveal_type(x) # N: Revealed type is "__main__.SE | __main__.Custom"
2925+
else:
2926+
reveal_type(x) # N: Revealed type is "builtins.str | __main__.Custom | __main__.SE"
2927+
2928+
if x == str():
2929+
reveal_type(x) # N: Revealed type is "builtins.str | __main__.Custom"
2930+
else:
2931+
reveal_type(x) # N: Revealed type is "builtins.str | __main__.Custom | __main__.SE"
2932+
2933+
[builtins fixtures/primitives.pyi]

test-data/unit/check-isinstance.test

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2008,6 +2008,7 @@ else:
20082008
[builtins fixtures/list.pyi]
20092009

20102010
[case testNarrowTypeAfterInListNested]
2011+
# flags: --warn-unreachable
20112012
from typing import List, Optional, Any
20122013

20132014
x: Optional[int]
@@ -2019,7 +2020,6 @@ if lst in nested_any:
20192020
if x in nested_any:
20202021
reveal_type(x) # N: Revealed type is "builtins.int | None"
20212022
[builtins fixtures/list.pyi]
2022-
[out]
20232023

20242024
[case testNarrowTypeAfterInTuple]
20252025
from typing import Optional
@@ -2929,3 +2929,11 @@ if isinstance(a, B):
29292929
c = a
29302930

29312931
[builtins fixtures/isinstance.pyi]
2932+
2933+
[case testIsInstanceTypeAny]
2934+
from typing import Any
2935+
2936+
def foo(x: object, t: type[Any]):
2937+
if isinstance(x, t):
2938+
reveal_type(x) # N: Revealed type is "Any"
2939+
[builtins fixtures/isinstance.pyi]

test-data/unit/check-narrowing.test

Lines changed: 96 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -829,19 +829,19 @@ from typing import Literal, Union
829829
class Custom:
830830
def __eq__(self, other: object) -> bool: return True
831831

832-
class Default: pass
832+
def f1(x: Union[Custom, Literal[1], Literal[2]]):
833+
if x == 1:
834+
reveal_type(x) # N: Revealed type is "__main__.Custom | Literal[1]"
835+
else:
836+
reveal_type(x) # N: Revealed type is "__main__.Custom | Literal[2]"
833837

834-
x1: Union[Custom, Literal[1], Literal[2]]
835-
if x1 == 1:
836-
reveal_type(x1) # N: Revealed type is "__main__.Custom | Literal[1]"
837-
else:
838-
reveal_type(x1) # N: Revealed type is "__main__.Custom | Literal[2]"
838+
class Default: pass
839839

840-
x2: Union[Default, Literal[1], Literal[2]]
841-
if x2 == 1:
842-
reveal_type(x2) # N: Revealed type is "Literal[1]"
843-
else:
844-
reveal_type(x2) # N: Revealed type is "__main__.Default | Literal[2]"
840+
def f2(x: Union[Default, Literal[1], Literal[2]]):
841+
if x == 1:
842+
reveal_type(x) # N: Revealed type is "Literal[1]"
843+
else:
844+
reveal_type(x) # N: Revealed type is "__main__.Default | Literal[2]"
845845
[builtins fixtures/primitives.pyi]
846846

847847
[case testNarrowingEqualityCustomEqualityEnum]
@@ -875,25 +875,23 @@ from typing import Literal, Union
875875
class Custom:
876876
def __eq__(self, other: object) -> bool: return True
877877

878-
class Default: pass
879-
880-
x: Literal[1, 2, None]
881-
y: Custom
882-
z: Default
878+
def f1(x: Literal[1, 2, None], y: Custom):
879+
if 1 == x == y:
880+
reveal_type(x) # N: Revealed type is "Literal[1]"
881+
reveal_type(y) # N: Revealed type is "__main__.Custom"
882+
else:
883+
reveal_type(x) # N: Revealed type is "Literal[2] | None"
884+
reveal_type(y) # N: Revealed type is "__main__.Custom"
883885

884-
if 1 == x == y:
885-
reveal_type(x) # N: Revealed type is "Literal[1]"
886-
reveal_type(y) # N: Revealed type is "__main__.Custom"
887-
else:
888-
reveal_type(x) # N: Revealed type is "Literal[2] | None"
889-
reveal_type(y) # N: Revealed type is "__main__.Custom"
886+
class Default: pass
890887

891-
if 1 == x == z: # E: Non-overlapping equality check (left operand type: "Literal[1, 2] | None", right operand type: "Default")
892-
reveal_type(x) # E: Statement is unreachable
893-
reveal_type(z)
894-
else:
895-
reveal_type(x) # N: Revealed type is "Literal[1] | Literal[2] | None"
896-
reveal_type(z) # N: Revealed type is "__main__.Default"
888+
def f2(x: Literal[1, 2, None], z: Default):
889+
if 1 == x == z: # E: Non-overlapping equality check (left operand type: "Literal[1, 2] | None", right operand type: "Default")
890+
reveal_type(x) # E: Statement is unreachable
891+
reveal_type(z)
892+
else:
893+
reveal_type(x) # N: Revealed type is "Literal[1] | Literal[2] | None"
894+
reveal_type(z) # N: Revealed type is "__main__.Default"
897895
[builtins fixtures/primitives.pyi]
898896

899897
[case testNarrowingCustomEqualityLiteralElseBranch]
@@ -1445,19 +1443,23 @@ if val not in (None,):
14451443
reveal_type(val) # N: Revealed type is "__main__.A"
14461444
else:
14471445
reveal_type(val) # N: Revealed type is "None"
1446+
[builtins fixtures/primitives.pyi]
14481447

1449-
class Hmm:
1448+
[case testNarrowingCustomEqualityOptionalEqualsNone]
1449+
# flags: --strict-equality --warn-unreachable
1450+
from __future__ import annotations
1451+
class Custom:
14501452
def __eq__(self, other) -> bool: ...
14511453

1452-
hmm: Optional[Hmm]
1453-
if hmm == None:
1454-
reveal_type(hmm) # N: Revealed type is "__main__.Hmm | None"
1455-
else:
1456-
reveal_type(hmm) # N: Revealed type is "__main__.Hmm"
1457-
if hmm != None:
1458-
reveal_type(hmm) # N: Revealed type is "__main__.Hmm"
1459-
else:
1460-
reveal_type(hmm) # N: Revealed type is "__main__.Hmm | None"
1454+
def f(x: Custom | None):
1455+
if x == None:
1456+
reveal_type(x) # N: Revealed type is "__main__.Custom | None"
1457+
else:
1458+
reveal_type(x) # N: Revealed type is "__main__.Custom"
1459+
if x != None:
1460+
reveal_type(x) # N: Revealed type is "__main__.Custom"
1461+
else:
1462+
reveal_type(x) # N: Revealed type is "__main__.Custom | None"
14611463
[builtins fixtures/primitives.pyi]
14621464

14631465
[case testNarrowingWithTupleOfTypes]
@@ -2992,6 +2994,62 @@ def f2(x: Any) -> None:
29922994
reveal_type(x) # N: Revealed type is "Any"
29932995
[builtins fixtures/tuple.pyi]
29942996

2997+
[case testNarrowTypeObject]
2998+
# flags: --strict-equality --warn-unreachable
2999+
from typing import Any
3000+
3001+
# https://github.com/python/mypy/issues/13704
3002+
3003+
def f1(cls: type):
3004+
if cls is str:
3005+
reveal_type(cls) # N: Revealed type is "def (o: builtins.object =) -> builtins.str"
3006+
reveal_type(cls(5)) # N: Revealed type is "builtins.str"
3007+
3008+
if issubclass(cls, int):
3009+
pass
3010+
elif cls is str:
3011+
reveal_type(cls) # N: Revealed type is "type[builtins.object]"
3012+
reveal_type(cls(5)) # E: Too many arguments for "object" \
3013+
# N: Revealed type is "builtins.object"
3014+
3015+
def f2(cls: type[object]):
3016+
if cls is str:
3017+
reveal_type(cls) # N: Revealed type is "type[builtins.object]"
3018+
reveal_type(cls(5)) # E: Too many arguments for "object" \
3019+
# N: Revealed type is "builtins.object"
3020+
3021+
if issubclass(cls, int):
3022+
pass
3023+
elif cls is str:
3024+
reveal_type(cls) # N: Revealed type is "type[builtins.object]"
3025+
reveal_type(cls(5)) # E: Too many arguments for "object" \
3026+
# N: Revealed type is "builtins.object"
3027+
3028+
def f3(cls: type[Any]):
3029+
if cls is str:
3030+
reveal_type(cls) # N: Revealed type is "type[Any]"
3031+
reveal_type(cls(5)) # N: Revealed type is "Any"
3032+
3033+
if issubclass(cls, int):
3034+
pass
3035+
elif cls is str:
3036+
reveal_type(cls) # N: Revealed type is "type[Any]"
3037+
reveal_type(cls(5)) # N: Revealed type is "Any"
3038+
[builtins fixtures/isinstance.pyi]
3039+
3040+
[case testNarrowTypeObjectUnion]
3041+
# flags: --strict-equality --warn-unreachable
3042+
from __future__ import annotations
3043+
3044+
def f4(cls: type[str | int]):
3045+
reveal_type(cls) # N: Revealed type is "type[builtins.str] | type[builtins.int]"
3046+
3047+
if cls is int:
3048+
reveal_type(cls) # N: Revealed type is "type[builtins.int]"
3049+
if cls == int:
3050+
reveal_type(cls) # N: Revealed type is "type[builtins.int]"
3051+
[builtins fixtures/primitives.pyi]
3052+
29953053
[case testTypeEqualsCheck]
29963054
# flags: --strict-equality --warn-unreachable
29973055
from typing import Any

test-data/unit/fixtures/isinstance.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class int:
2222
class float: pass
2323
class bool(int): pass
2424
class str:
25+
def __new__(cls, o: object = ...) -> str: pass
2526
def __add__(self, other: 'str') -> 'str': pass
2627
class ellipsis: pass
2728

0 commit comments

Comments
 (0)