| -- This test file checks Enum |
| |
| [case testEnumBasics] |
| from enum import Enum |
| class Medal(Enum): |
| gold = 1 |
| silver = 2 |
| bronze = 3 |
| reveal_type(Medal.bronze) # N: Revealed type is '__main__.Medal*' |
| m = Medal.gold |
| if int(): |
| m = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "Medal") |
| |
| [case testEnumFromEnumMetaBasics] |
| from enum import EnumMeta |
| class Medal(metaclass=EnumMeta): |
| gold = 1 |
| silver = "hello" |
| bronze = None |
| # Without __init__ the definition fails at runtime, but we want to verify that mypy |
| # uses `enum.EnumMeta` and not `enum.Enum` as the definition of what is enum. |
| def __init__(self, *args): pass |
| reveal_type(Medal.bronze) # N: Revealed type is '__main__.Medal' |
| m = Medal.gold |
| if int(): |
| m = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "Medal") |
| |
| [case testEnumFromEnumMetaSubclass] |
| from enum import EnumMeta |
| class Achievement(metaclass=EnumMeta): pass |
| class Medal(Achievement): |
| gold = 1 |
| silver = "hello" |
| bronze = None |
| # See comment in testEnumFromEnumMetaBasics |
| def __init__(self, *args): pass |
| reveal_type(Medal.bronze) # N: Revealed type is '__main__.Medal' |
| m = Medal.gold |
| if int(): |
| m = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "Medal") |
| |
| [case testEnumFromEnumMetaGeneric] |
| from enum import EnumMeta |
| from typing import Generic, TypeVar |
| T = TypeVar("T") |
| class Medal(Generic[T], metaclass=EnumMeta): # E: Enum class cannot be generic |
| q = None |
| |
| [case testEnumNameAndValue] |
| from enum import Enum |
| class Truth(Enum): |
| true = True |
| false = False |
| x = '' |
| x = Truth.true.name |
| reveal_type(Truth.true.name) # N: Revealed type is 'builtins.str' |
| reveal_type(Truth.false.value) # N: Revealed type is 'builtins.bool' |
| [builtins fixtures/bool.pyi] |
| |
| [case testEnumUnique] |
| import enum |
| @enum.unique |
| class E(enum.Enum): |
| x = 1 |
| y = 1 # NOTE: This duplicate value is not detected by mypy at the moment |
| x = 1 |
| x = E.x |
| [out] |
| main:7: error: Incompatible types in assignment (expression has type "E", variable has type "int") |
| |
| [case testIntEnum_assignToIntVariable] |
| from enum import IntEnum |
| class N(IntEnum): |
| x = 1 |
| y = 1 |
| n = 1 |
| if int(): |
| n = N.x # Subclass of int, so it's okay |
| s = '' |
| if int(): |
| s = N.y # E: Incompatible types in assignment (expression has type "N", variable has type "str") |
| |
| [case testIntEnum_functionTakingIntEnum] |
| from enum import IntEnum |
| class SomeIntEnum(IntEnum): |
| x = 1 |
| def takes_some_int_enum(n: SomeIntEnum): |
| pass |
| takes_some_int_enum(SomeIntEnum.x) |
| takes_some_int_enum(1) # Error |
| takes_some_int_enum(SomeIntEnum(1)) # How to deal with the above |
| [out] |
| main:7: error: Argument 1 to "takes_some_int_enum" has incompatible type "int"; expected "SomeIntEnum" |
| |
| [case testIntEnum_functionTakingInt] |
| from enum import IntEnum |
| class SomeIntEnum(IntEnum): |
| x = 1 |
| def takes_int(i: int): |
| pass |
| takes_int(SomeIntEnum.x) |
| takes_int(2) |
| |
| [case testIntEnum_functionReturningIntEnum] |
| from enum import IntEnum |
| class SomeIntEnum(IntEnum): |
| x = 1 |
| def returns_some_int_enum() -> SomeIntEnum: |
| return SomeIntEnum.x |
| an_int = 1 |
| an_int = returns_some_int_enum() |
| |
| an_enum = SomeIntEnum.x |
| an_enum = returns_some_int_enum() |
| [out] |
| |
| [case testEnumMethods] |
| from enum import Enum |
| |
| class Color(Enum): |
| red = 1 |
| green = 2 |
| |
| def m(self, x: int): pass |
| @staticmethod |
| def m2(x: int): pass |
| |
| Color.red.m('') |
| Color.m2('') |
| [builtins fixtures/staticmethod.pyi] |
| [out] |
| main:11: error: Argument 1 to "m" of "Color" has incompatible type "str"; expected "int" |
| main:12: error: Argument 1 to "m2" of "Color" has incompatible type "str"; expected "int" |
| |
| [case testIntEnum_ExtendedIntEnum_functionTakingExtendedIntEnum] |
| from enum import IntEnum |
| class ExtendedIntEnum(IntEnum): |
| pass |
| class SomeExtIntEnum(ExtendedIntEnum): |
| x = 1 |
| |
| def takes_int(i: int): |
| pass |
| takes_int(SomeExtIntEnum.x) |
| |
| def takes_some_ext_int_enum(s: SomeExtIntEnum): |
| pass |
| takes_some_ext_int_enum(SomeExtIntEnum.x) |
| |
| [case testNamedTupleEnum] |
| from typing import NamedTuple |
| from enum import Enum |
| |
| N = NamedTuple('N', [('bar', int)]) |
| |
| class E(N, Enum): |
| X = N(1) |
| |
| def f(x: E) -> None: pass |
| |
| f(E.X) |
| |
| [case testEnumCall] |
| from enum import IntEnum |
| class E(IntEnum): |
| a = 1 |
| x = None # type: int |
| reveal_type(E(x)) |
| [out] |
| main:5: note: Revealed type is '__main__.E*' |
| |
| [case testEnumIndex] |
| from enum import IntEnum |
| class E(IntEnum): |
| a = 1 |
| s = None # type: str |
| reveal_type(E[s]) |
| [out] |
| main:5: note: Revealed type is '__main__.E' |
| |
| [case testEnumIndexError] |
| from enum import IntEnum |
| class E(IntEnum): |
| a = 1 |
| E[1] # E: Enum index should be a string (actual index type "int") |
| x = E[1] # E: Enum index should be a string (actual index type "int") |
| |
| [case testEnumIndexIsNotAnAlias] |
| from enum import Enum |
| |
| class E(Enum): |
| a = 1 |
| b = 2 |
| reveal_type(E['a']) # N: Revealed type is '__main__.E' |
| E['a'] |
| x = E['a'] |
| reveal_type(x) # N: Revealed type is '__main__.E' |
| |
| def get_member(name: str) -> E: |
| val = E[name] |
| return val |
| |
| reveal_type(get_member('a')) # N: Revealed type is '__main__.E' |
| |
| [case testGenericEnum] |
| from enum import Enum |
| from typing import Generic, TypeVar |
| |
| T = TypeVar('T') |
| |
| class F(Generic[T], Enum): # E: Enum class cannot be generic |
| x: T |
| y: T |
| |
| reveal_type(F[int].x) # N: Revealed type is '__main__.F[builtins.int*]' |
| |
| [case testEnumFlag] |
| from enum import Flag |
| class C(Flag): |
| a = 1 |
| b = 2 |
| x = C.a |
| if int(): |
| x = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "C") |
| if int(): |
| x = x | C.b |
| |
| [case testEnumIntFlag] |
| from enum import IntFlag |
| class C(IntFlag): |
| a = 1 |
| b = 2 |
| x = C.a |
| if int(): |
| x = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "C") |
| if int(): |
| x = x | C.b |
| |
| [case testAnonymousEnum] |
| from enum import Enum |
| class A: |
| def f(self) -> None: |
| class E(Enum): |
| a = 1 |
| self.x = E.a |
| a = A() |
| reveal_type(a.x) |
| [out] |
| main:8: note: Revealed type is '__main__.E@4*' |
| |
| [case testEnumInClassBody] |
| from enum import Enum |
| class A: |
| class E(Enum): |
| a = 1 |
| class B: |
| class E(Enum): |
| a = 1 |
| x = A.E.a |
| y = B.E.a |
| if int(): |
| x = y # E: Incompatible types in assignment (expression has type "__main__.B.E", variable has type "__main__.A.E") |
| |
| [case testFunctionalEnumString] |
| from enum import Enum, IntEnum |
| E = Enum('E', 'foo bar') |
| I = IntEnum('I', ' bar, baz ') |
| reveal_type(E.foo) |
| reveal_type(E.bar.value) |
| reveal_type(I.bar) |
| reveal_type(I.baz.value) |
| [out] |
| main:4: note: Revealed type is '__main__.E*' |
| main:5: note: Revealed type is 'Any' |
| main:6: note: Revealed type is '__main__.I*' |
| main:7: note: Revealed type is 'builtins.int' |
| |
| [case testFunctionalEnumListOfStrings] |
| from enum import Enum, IntEnum |
| E = Enum('E', ('foo', 'bar')) |
| F = IntEnum('F', ['bar', 'baz']) |
| reveal_type(E.foo) |
| reveal_type(F.baz) |
| [out] |
| main:4: note: Revealed type is '__main__.E*' |
| main:5: note: Revealed type is '__main__.F*' |
| |
| [case testFunctionalEnumListOfPairs] |
| from enum import Enum, IntEnum |
| E = Enum('E', [('foo', 1), ['bar', 2]]) |
| F = IntEnum('F', (['bar', 1], ('baz', 2))) |
| reveal_type(E.foo) |
| reveal_type(F.baz) |
| reveal_type(E.foo.value) |
| reveal_type(F.bar.name) |
| [out] |
| main:4: note: Revealed type is '__main__.E*' |
| main:5: note: Revealed type is '__main__.F*' |
| main:6: note: Revealed type is 'builtins.int' |
| main:7: note: Revealed type is 'builtins.str' |
| |
| [case testFunctionalEnumDict] |
| from enum import Enum, IntEnum |
| E = Enum('E', {'foo': 1, 'bar': 2}) |
| F = IntEnum('F', {'bar': 1, 'baz': 2}) |
| reveal_type(E.foo) |
| reveal_type(F.baz) |
| reveal_type(E.foo.value) |
| reveal_type(F.bar.name) |
| [out] |
| main:4: note: Revealed type is '__main__.E*' |
| main:5: note: Revealed type is '__main__.F*' |
| main:6: note: Revealed type is 'builtins.int' |
| main:7: note: Revealed type is 'builtins.str' |
| |
| [case testFunctionalEnumErrors] |
| from enum import Enum, IntEnum |
| A = Enum('A') |
| B = Enum('B', 42) |
| C = Enum('C', 'a b', 'x') |
| D = Enum('D', foo) |
| bar = 'x y z' |
| E = Enum('E', bar) |
| I = IntEnum('I') |
| J = IntEnum('I', 42) |
| K = IntEnum('I', 'p q', 'z') |
| L = Enum('L', ' ') |
| M = Enum('M', ()) |
| N = IntEnum('M', []) |
| P = Enum('P', [42]) |
| Q = Enum('Q', [('a', 42, 0)]) |
| R = IntEnum('R', [[0, 42]]) |
| S = Enum('S', {1: 1}) |
| T = Enum('T', keyword='a b') |
| U = Enum('U', *['a']) |
| V = Enum('U', **{'a': 1}) |
| W = Enum('W', 'a b') |
| W.c |
| [typing fixtures/typing-full.pyi] |
| [out] |
| main:2: error: Too few arguments for Enum() |
| main:3: error: Enum() expects a string, tuple, list or dict literal as the second argument |
| main:4: error: Too many arguments for Enum() |
| main:5: error: Enum() expects a string, tuple, list or dict literal as the second argument |
| main:5: error: Name 'foo' is not defined |
| main:7: error: Enum() expects a string, tuple, list or dict literal as the second argument |
| main:8: error: Too few arguments for IntEnum() |
| main:9: error: IntEnum() expects a string, tuple, list or dict literal as the second argument |
| main:10: error: Too many arguments for IntEnum() |
| main:11: error: Enum() needs at least one item |
| main:12: error: Enum() needs at least one item |
| main:13: error: IntEnum() needs at least one item |
| main:14: error: Enum() with tuple or list expects strings or (name, value) pairs |
| main:15: error: Enum() with tuple or list expects strings or (name, value) pairs |
| main:16: error: IntEnum() with tuple or list expects strings or (name, value) pairs |
| main:17: error: Enum() with dict literal requires string literals |
| main:18: error: Unexpected arguments to Enum() |
| main:19: error: Unexpected arguments to Enum() |
| main:20: error: Unexpected arguments to Enum() |
| main:22: error: "Type[W]" has no attribute "c" |
| |
| [case testFunctionalEnumFlag] |
| from enum import Flag, IntFlag |
| A = Flag('A', 'x y') |
| B = IntFlag('B', 'a b') |
| reveal_type(A.x) # N: Revealed type is '__main__.A*' |
| reveal_type(B.a) # N: Revealed type is '__main__.B*' |
| reveal_type(A.x.name) # N: Revealed type is 'builtins.str' |
| reveal_type(B.a.name) # N: Revealed type is 'builtins.str' |
| |
| # TODO: The revealed type should be 'int' here |
| reveal_type(A.x.value) # N: Revealed type is 'Any' |
| reveal_type(B.a.value) # N: Revealed type is 'Any' |
| |
| [case testAnonymousFunctionalEnum] |
| from enum import Enum |
| class A: |
| def f(self) -> None: |
| E = Enum('E', 'a b') |
| self.x = E.a |
| a = A() |
| reveal_type(a.x) |
| [out] |
| main:7: note: Revealed type is '__main__.A.E@4*' |
| |
| [case testFunctionalEnumInClassBody] |
| from enum import Enum |
| class A: |
| E = Enum('E', 'a b') |
| class B: |
| E = Enum('E', 'a b') |
| x = A.E.a |
| y = B.E.a |
| if int(): |
| x = y # E: Incompatible types in assignment (expression has type "__main__.B.E", variable has type "__main__.A.E") |
| |
| [case testFunctionalEnumProtocols] |
| from enum import IntEnum |
| Color = IntEnum('Color', 'red green blue') |
| reveal_type(Color['green']) # N: Revealed type is '__main__.Color' |
| for c in Color: |
| reveal_type(c) # N: Revealed type is '__main__.Color*' |
| reveal_type(list(Color)) # N: Revealed type is 'builtins.list[__main__.Color*]' |
| |
| [builtins fixtures/list.pyi] |
| |
| [case testEnumWorkWithForward] |
| from enum import Enum |
| a: E = E.x |
| class E(Enum): |
| x = 1 |
| y = 2 |
| [out] |
| |
| [case testEnumWorkWithForward2] |
| from enum import Enum |
| b: F |
| F = Enum('F', {'x': 1, 'y': 2}) |
| |
| def fn(x: F) -> None: |
| pass |
| fn(b) |
| [out] |
| |
| [case testFunctionalEnum_python2] |
| from enum import Enum |
| Eu = Enum(u'Eu', u'a b') |
| Eb = Enum(b'Eb', b'a b') |
| Gu = Enum(u'Gu', {u'a': 1}) |
| Gb = Enum(b'Gb', {b'a': 1}) |
| Hu = Enum(u'Hu', [u'a']) |
| Hb = Enum(b'Hb', [b'a']) |
| Eu.a |
| Eb.a |
| Gu.a |
| Gb.a |
| Hu.a |
| Hb.a |
| [out] |
| |
| [case testEnumIncremental] |
| import m |
| reveal_type(m.E.a) |
| reveal_type(m.F.b) |
| [file m.py] |
| from enum import Enum |
| class E(Enum): |
| a = 1 |
| b = 2 |
| F = Enum('F', 'a b') |
| [rechecked] |
| [stale] |
| [out1] |
| main:2: note: Revealed type is 'm.E*' |
| main:3: note: Revealed type is 'm.F*' |
| [out2] |
| main:2: note: Revealed type is 'm.E*' |
| main:3: note: Revealed type is 'm.F*' |
| |
| [case testEnumAuto] |
| from enum import Enum, auto |
| class Test(Enum): |
| a = auto() |
| b = auto() |
| |
| reveal_type(Test.a) # N: Revealed type is '__main__.Test*' |
| [builtins fixtures/primitives.pyi] |
| |
| [case testEnumAttributeAccessMatrix] |
| from enum import Enum, IntEnum, IntFlag, Flag, EnumMeta, auto |
| from typing_extensions import Literal |
| |
| def is_x(val: Literal['x']) -> None: pass |
| |
| A1 = Enum('A1', 'x') |
| class A2(Enum): |
| x = auto() |
| class A3(Enum): |
| x = 1 |
| |
| is_x(reveal_type(A1.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(A1.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(A1.x.value) # N: Revealed type is 'Any' |
| reveal_type(A1.x._value_) # N: Revealed type is 'Any' |
| is_x(reveal_type(A2.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(A2.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(A2.x.value) # N: Revealed type is 'Any' |
| reveal_type(A2.x._value_) # N: Revealed type is 'Any' |
| is_x(reveal_type(A3.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(A3.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(A3.x.value) # N: Revealed type is 'builtins.int' |
| reveal_type(A3.x._value_) # N: Revealed type is 'builtins.int' |
| |
| B1 = IntEnum('B1', 'x') |
| class B2(IntEnum): |
| x = auto() |
| class B3(IntEnum): |
| x = 1 |
| |
| # TODO: getting B1.x._value_ and B2.x._value_ to have type 'int' requires a typeshed change |
| |
| is_x(reveal_type(B1.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(B1.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(B1.x.value) # N: Revealed type is 'builtins.int' |
| reveal_type(B1.x._value_) # N: Revealed type is 'Any' |
| is_x(reveal_type(B2.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(B2.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(B2.x.value) # N: Revealed type is 'builtins.int' |
| reveal_type(B2.x._value_) # N: Revealed type is 'Any' |
| is_x(reveal_type(B3.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(B3.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(B3.x.value) # N: Revealed type is 'builtins.int' |
| reveal_type(B3.x._value_) # N: Revealed type is 'builtins.int' |
| |
| # TODO: C1.x.value and C2.x.value should also be of type 'int' |
| # This requires either a typeshed change or a plugin refinement |
| |
| C1 = IntFlag('C1', 'x') |
| class C2(IntFlag): |
| x = auto() |
| class C3(IntFlag): |
| x = 1 |
| |
| is_x(reveal_type(C1.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(C1.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(C1.x.value) # N: Revealed type is 'Any' |
| reveal_type(C1.x._value_) # N: Revealed type is 'Any' |
| is_x(reveal_type(C2.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(C2.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(C2.x.value) # N: Revealed type is 'Any' |
| reveal_type(C2.x._value_) # N: Revealed type is 'Any' |
| is_x(reveal_type(C3.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(C3.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(C3.x.value) # N: Revealed type is 'builtins.int' |
| reveal_type(C3.x._value_) # N: Revealed type is 'builtins.int' |
| |
| D1 = Flag('D1', 'x') |
| class D2(Flag): |
| x = auto() |
| class D3(Flag): |
| x = 1 |
| |
| is_x(reveal_type(D1.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(D1.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(D1.x.value) # N: Revealed type is 'Any' |
| reveal_type(D1.x._value_) # N: Revealed type is 'Any' |
| is_x(reveal_type(D2.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(D2.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(D2.x.value) # N: Revealed type is 'Any' |
| reveal_type(D2.x._value_) # N: Revealed type is 'Any' |
| is_x(reveal_type(D3.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(D3.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(D3.x.value) # N: Revealed type is 'builtins.int' |
| reveal_type(D3.x._value_) # N: Revealed type is 'builtins.int' |
| |
| # TODO: Generalize our enum functional API logic to work with subclasses of Enum |
| # See https://github.com/python/mypy/issues/6037 |
| |
| class Parent(Enum): pass |
| # E1 = Parent('E1', 'x') # See above TODO |
| class E2(Parent): |
| x = auto() |
| class E3(Parent): |
| x = 1 |
| |
| is_x(reveal_type(E2.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(E2.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(E2.x.value) # N: Revealed type is 'Any' |
| reveal_type(E2.x._value_) # N: Revealed type is 'Any' |
| is_x(reveal_type(E3.x.name)) # N: Revealed type is 'Literal['x']' |
| is_x(reveal_type(E3.x._name_)) # N: Revealed type is 'Literal['x']' |
| reveal_type(E3.x.value) # N: Revealed type is 'builtins.int' |
| reveal_type(E3.x._value_) # N: Revealed type is 'builtins.int' |
| |
| |
| # TODO: Figure out if we can construct enums using EnumMetas using the functional API. |
| # Also figure out if we even care about supporting that use case. |
| class F2(metaclass=EnumMeta): |
| x = auto() |
| class F3(metaclass=EnumMeta): |
| x = 1 |
| |
| F2.x.name # E: "F2" has no attribute "name" |
| F2.x._name_ # E: "F2" has no attribute "_name_" |
| F2.x.value # E: "F2" has no attribute "value" |
| F2.x._value_ # E: "F2" has no attribute "_value_" |
| F3.x.name # E: "F3" has no attribute "name" |
| F3.x._name_ # E: "F3" has no attribute "_name_" |
| F3.x.value # E: "F3" has no attribute "value" |
| F3.x._value_ # E: "F3" has no attribute "_value_" |
| [builtins fixtures/primitives.pyi] |
| |
| [case testEnumAttributeChangeIncremental] |
| from a import SomeEnum |
| reveal_type(SomeEnum.a.value) |
| |
| [file a.py] |
| from b import SomeEnum |
| |
| [file b.py] |
| from enum import Enum |
| class SomeEnum(Enum): |
| a = 1 |
| |
| [file b.py.2] |
| from enum import Enum |
| class SomeEnum(Enum): |
| a = "foo" |
| [out] |
| main:2: note: Revealed type is 'builtins.int' |
| [out2] |
| main:2: note: Revealed type is 'builtins.str' |
| |
| [case testEnumReachabilityChecksBasic] |
| from enum import Enum |
| from typing_extensions import Literal |
| |
| class Foo(Enum): |
| A = 1 |
| B = 2 |
| C = 3 |
| |
| x: Literal[Foo.A, Foo.B, Foo.C] |
| if x is Foo.A: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| elif x is Foo.B: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Foo.B]' |
| elif x is Foo.C: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Foo.C]' |
| else: |
| reveal_type(x) # No output here: this branch is unreachable |
| |
| if Foo.A is x: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| elif Foo.B is x: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Foo.B]' |
| elif Foo.C is x: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Foo.C]' |
| else: |
| reveal_type(x) # No output here: this branch is unreachable |
| |
| y: Foo |
| if y is Foo.A: |
| reveal_type(y) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| elif y is Foo.B: |
| reveal_type(y) # N: Revealed type is 'Literal[__main__.Foo.B]' |
| elif y is Foo.C: |
| reveal_type(y) # N: Revealed type is 'Literal[__main__.Foo.C]' |
| else: |
| reveal_type(y) # No output here: this branch is unreachable |
| |
| if Foo.A is y: |
| reveal_type(y) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| elif Foo.B is y: |
| reveal_type(y) # N: Revealed type is 'Literal[__main__.Foo.B]' |
| elif Foo.C is y: |
| reveal_type(y) # N: Revealed type is 'Literal[__main__.Foo.C]' |
| else: |
| reveal_type(y) # No output here: this branch is unreachable |
| [builtins fixtures/bool.pyi] |
| |
| [case testEnumReachabilityChecksIndirect] |
| from enum import Enum |
| from typing_extensions import Literal, Final |
| |
| class Foo(Enum): |
| A = 1 |
| B = 2 |
| C = 3 |
| |
| def accepts_foo_a(x: Literal[Foo.A]) -> None: ... |
| |
| x: Foo |
| y: Literal[Foo.A] |
| z: Final = Foo.A |
| |
| if x is y: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| reveal_type(y) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| else: |
| reveal_type(x) # N: Revealed type is 'Union[Literal[__main__.Foo.B], Literal[__main__.Foo.C]]' |
| reveal_type(y) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| if y is x: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| reveal_type(y) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| else: |
| reveal_type(x) # N: Revealed type is 'Union[Literal[__main__.Foo.B], Literal[__main__.Foo.C]]' |
| reveal_type(y) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| |
| if x is z: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| reveal_type(z) # N: Revealed type is '__main__.Foo*' |
| accepts_foo_a(z) |
| else: |
| reveal_type(x) # N: Revealed type is 'Union[Literal[__main__.Foo.B], Literal[__main__.Foo.C]]' |
| reveal_type(z) # N: Revealed type is '__main__.Foo*' |
| accepts_foo_a(z) |
| if z is x: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| reveal_type(z) # N: Revealed type is '__main__.Foo*' |
| accepts_foo_a(z) |
| else: |
| reveal_type(x) # N: Revealed type is 'Union[Literal[__main__.Foo.B], Literal[__main__.Foo.C]]' |
| reveal_type(z) # N: Revealed type is '__main__.Foo*' |
| accepts_foo_a(z) |
| |
| if y is z: |
| reveal_type(y) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| reveal_type(z) # N: Revealed type is '__main__.Foo*' |
| accepts_foo_a(z) |
| else: |
| reveal_type(y) # No output: this branch is unreachable |
| reveal_type(z) # No output: this branch is unreachable |
| if z is y: |
| reveal_type(y) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| reveal_type(z) # N: Revealed type is '__main__.Foo*' |
| accepts_foo_a(z) |
| else: |
| reveal_type(y) # No output: this branch is unreachable |
| reveal_type(z) # No output: this branch is unreachable |
| [builtins fixtures/bool.pyi] |
| |
| [case testEnumReachabilityNoNarrowingForUnionMessiness] |
| from enum import Enum |
| from typing_extensions import Literal |
| |
| class Foo(Enum): |
| A = 1 |
| B = 2 |
| C = 3 |
| |
| x: Foo |
| y: Literal[Foo.A, Foo.B] |
| z: Literal[Foo.B, Foo.C] |
| |
| # For the sake of simplicity, no narrowing is done when the narrower type is a Union. |
| if x is y: |
| reveal_type(x) # N: Revealed type is '__main__.Foo' |
| reveal_type(y) # N: Revealed type is 'Union[Literal[__main__.Foo.A], Literal[__main__.Foo.B]]' |
| else: |
| reveal_type(x) # N: Revealed type is '__main__.Foo' |
| reveal_type(y) # N: Revealed type is 'Union[Literal[__main__.Foo.A], Literal[__main__.Foo.B]]' |
| |
| if y is z: |
| reveal_type(y) # N: Revealed type is 'Union[Literal[__main__.Foo.A], Literal[__main__.Foo.B]]' |
| reveal_type(z) # N: Revealed type is 'Union[Literal[__main__.Foo.B], Literal[__main__.Foo.C]]' |
| else: |
| reveal_type(y) # N: Revealed type is 'Union[Literal[__main__.Foo.A], Literal[__main__.Foo.B]]' |
| reveal_type(z) # N: Revealed type is 'Union[Literal[__main__.Foo.B], Literal[__main__.Foo.C]]' |
| [builtins fixtures/bool.pyi] |
| |
| [case testEnumReachabilityWithNone] |
| # flags: --strict-optional |
| from enum import Enum |
| from typing import Optional |
| |
| class Foo(Enum): |
| A = 1 |
| B = 2 |
| C = 3 |
| |
| x: Optional[Foo] |
| if x: |
| reveal_type(x) # N: Revealed type is '__main__.Foo' |
| else: |
| reveal_type(x) # N: Revealed type is 'Union[__main__.Foo, None]' |
| |
| if x is not None: |
| reveal_type(x) # N: Revealed type is '__main__.Foo' |
| else: |
| reveal_type(x) # N: Revealed type is 'None' |
| |
| if x is Foo.A: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| else: |
| reveal_type(x) # N: Revealed type is 'Union[Literal[__main__.Foo.B], Literal[__main__.Foo.C], None]' |
| [builtins fixtures/bool.pyi] |
| |
| [case testEnumReachabilityWithMultipleEnums] |
| from enum import Enum |
| from typing import Union |
| from typing_extensions import Literal |
| |
| class Foo(Enum): |
| A = 1 |
| B = 2 |
| class Bar(Enum): |
| A = 1 |
| B = 2 |
| |
| x1: Union[Foo, Bar] |
| if x1 is Foo.A: |
| reveal_type(x1) # N: Revealed type is 'Literal[__main__.Foo.A]' |
| else: |
| reveal_type(x1) # N: Revealed type is 'Union[Literal[__main__.Foo.B], __main__.Bar]' |
| |
| x2: Union[Foo, Bar] |
| if x2 is Bar.A: |
| reveal_type(x2) # N: Revealed type is 'Literal[__main__.Bar.A]' |
| else: |
| reveal_type(x2) # N: Revealed type is 'Union[__main__.Foo, Literal[__main__.Bar.B]]' |
| |
| x3: Union[Foo, Bar] |
| if x3 is Foo.A or x3 is Bar.A: |
| reveal_type(x3) # N: Revealed type is 'Union[Literal[__main__.Foo.A], Literal[__main__.Bar.A]]' |
| else: |
| reveal_type(x3) # N: Revealed type is 'Union[Literal[__main__.Foo.B], Literal[__main__.Bar.B]]' |
| |
| [builtins fixtures/bool.pyi] |
| |
| [case testEnumReachabilityPEP484ExampleWithFinal] |
| # flags: --strict-optional |
| from typing import Union |
| from typing_extensions import Final |
| from enum import Enum |
| |
| class Empty(Enum): |
| token = 0 |
| _empty: Final = Empty.token |
| |
| def func(x: Union[int, None, Empty] = _empty) -> int: |
| boom = x + 42 # E: Unsupported left operand type for + ("None") \ |
| # E: Unsupported left operand type for + ("Empty") \ |
| # N: Left operand is of type "Union[int, None, Empty]" |
| if x is _empty: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Empty.token]' |
| return 0 |
| elif x is None: |
| reveal_type(x) # N: Revealed type is 'None' |
| return 1 |
| else: # At this point typechecker knows that x can only have type int |
| reveal_type(x) # N: Revealed type is 'builtins.int' |
| return x + 2 |
| [builtins fixtures/primitives.pyi] |
| |
| [case testEnumReachabilityPEP484ExampleWithMultipleValues] |
| from typing import Union |
| from enum import Enum |
| |
| class Reason(Enum): |
| timeout = 1 |
| error = 2 |
| |
| def process(response: Union[str, Reason] = '') -> str: |
| if response is Reason.timeout: |
| reveal_type(response) # N: Revealed type is 'Literal[__main__.Reason.timeout]' |
| return 'TIMEOUT' |
| elif response is Reason.error: |
| reveal_type(response) # N: Revealed type is 'Literal[__main__.Reason.error]' |
| return 'ERROR' |
| else: |
| # response can be only str, all other possible values exhausted |
| reveal_type(response) # N: Revealed type is 'builtins.str' |
| return 'PROCESSED: ' + response |
| [builtins fixtures/primitives.pyi] |
| |
| |
| [case testEnumReachabilityPEP484ExampleSingleton] |
| # flags: --strict-optional |
| from typing import Union |
| from typing_extensions import Final |
| from enum import Enum |
| |
| class Empty(Enum): |
| token = 0 |
| _empty = Empty.token |
| |
| def func(x: Union[int, None, Empty] = _empty) -> int: |
| boom = x + 42 # E: Unsupported left operand type for + ("None") \ |
| # E: Unsupported left operand type for + ("Empty") \ |
| # N: Left operand is of type "Union[int, None, Empty]" |
| if x is _empty: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Empty.token]' |
| return 0 |
| elif x is None: |
| reveal_type(x) # N: Revealed type is 'None' |
| return 1 |
| else: # At this point typechecker knows that x can only have type int |
| reveal_type(x) # N: Revealed type is 'builtins.int' |
| return x + 2 |
| [builtins fixtures/primitives.pyi] |
| |
| [case testEnumReachabilityPEP484ExampleSingletonWithMethod] |
| # flags: --strict-optional |
| from typing import Union |
| from typing_extensions import Final |
| from enum import Enum |
| |
| class Empty(Enum): |
| token = lambda x: x |
| |
| def f(self) -> int: |
| return 1 |
| |
| _empty = Empty.token |
| |
| def func(x: Union[int, None, Empty] = _empty) -> int: |
| boom = x + 42 # E: Unsupported left operand type for + ("None") \ |
| # E: Unsupported left operand type for + ("Empty") \ |
| # N: Left operand is of type "Union[int, None, Empty]" |
| if x is _empty: |
| reveal_type(x) # N: Revealed type is 'Literal[__main__.Empty.token]' |
| return 0 |
| elif x is None: |
| reveal_type(x) # N: Revealed type is 'None' |
| return 1 |
| else: # At this point typechecker knows that x can only have type int |
| reveal_type(x) # N: Revealed type is 'builtins.int' |
| return x + 2 |
| [builtins fixtures/primitives.pyi] |