2Tests that the type checker can distinguish enum members from non-members.
5# Specification: https://typing.readthedocs.io/en/latest/spec/enums.html#defining-members
7from enum import Enum, member, nonmember
8from typing import Literal, assert_type, reveal_type
10# > If an attribute is defined in the class body with a type annotation but
11# > with no assigned value, a type checker should assume this is a non-member
16 genus: str # Non-member attribute
17 species: str # Non-member attribute
19 CAT = "felis", "catus" # Member attribute
20 DOG = "canis", "lupus" # Member attribute
22 def __init__(self, genus: str, species: str) -> None:
24 self.species = species
27def func1(pet: Pet) -> None:
28 assert_type(pet.genus, str)
29 assert_type(pet.species, str)
31assert_type(Pet.CAT, Literal[Pet.CAT])
32assert_type(Pet.DOG, Literal[Pet.DOG])
35from _enums_members import Pet2
37def func2(pet: Pet2) -> None:
38 assert_type(pet.genus, str)
39 assert_type(pet.species, str)
41assert_type(Pet2.CAT, Literal[Pet2.CAT])
42assert_type(Pet2.DOG, Literal[Pet2.DOG])
45# > Members defined within an enum class should not include explicit type
46# > annotations. Type checkers should infer a literal type for all members.
47# > A type checker should report an error if a type annotation is used for
48# > an enum member because this type will be incorrect and misleading to
49# > readers of the code
[invalid-enum-member-annotation] Type annotation on enum member `DOG` is not allowed
57# > Methods, callables, descriptors (including properties), and nested classes
58# > that are defined in the class are not treated as enum members by the
59# > EnumType metaclass and should likewise not be treated as enum members by a
63def identity(x: int) -> int:
68 CAT = 1 # Member attribute
69 DOG = 2 # Member attribute
71 converter = lambda x: str(x) # Non-member attribute
72 transform = staticmethod(identity) # Non-member attribute
75 def species(self) -> str: # Non-member property
78 def speak(self) -> None: # Non-member method
79 print("meow" if self is Pet4.CAT else "woof")
81 class Nested: ... # Non-member nested class
84assert_type(Pet4.CAT, Literal[Pet4.CAT])
85assert_type(Pet4.DOG, Literal[Pet4.DOG])
86converter: Literal[Pet4.converter] # E
[invalid-type-form] Type arguments for `Literal` must be `None`, a literal value (int, bool, str, or bytes), or an enum member
87transform: Literal[Pet4.transform] # E
[invalid-type-form] Type arguments for `Literal` must be `None`, a literal value (int, bool, str, or bytes), or an enum member
88species: Literal[Pet4.species] # E
[invalid-type-form] Type arguments for `Literal` must be `None`, a literal value (int, bool, str, or bytes), or an enum member
89speak: Literal[Pet4.speak] # E
[invalid-type-form] Type arguments for `Literal` must be `None`, a literal value (int, bool, str, or bytes), or an enum member
92# > An attribute that is assigned the value of another member of the same
93# > enum is not a member itself. Instead, it is an alias for the first member
96class TrafficLight(Enum):
101 AMBER = YELLOW # Alias for YELLOW
104assert_type(TrafficLight.AMBER, Literal[TrafficLight.YELLOW])
106# > If using Python 3.11 or newer, the enum.member and enum.nonmember classes
107# > can be used to unambiguously distinguish members from non-members.
111 a = member(1) # Member attribute
112 b = nonmember(2) # Non-member attribute
115 def c(self) -> None: # Member method
119assert_type(Example.a, Literal[Example.a])
120assert_type(Example.b, Literal[Example.b]) # E
[type-assertion-failure] Type `int` does not match asserted type `Unknown`
[invalid-type-form] Type arguments for `Literal` must be `None`, a literal value (int, bool, str, or bytes), or an enum member
121assert_type(Example.c, Literal[Example.c])
124# > An attribute with a private name (beginning with, but not ending in,
125# > a double underscore) is treated as a non-member.
129 __B = 2 # Non-member attribute
132 reveal_type(Example2.__B)
[revealed-type] Revealed type: `int`
133 assert_type(Example2.__B, Literal[Example2.__B]) # E
[type-assertion-failure] Type `int` does not match asserted type `Unknown`
[invalid-type-form] Type arguments for `Literal` must be `None`, a literal value (int, bool, str, or bytes), or an enum member
136# > An enum class can define a class symbol named _ignore_. This can be
137# > a list of names or a string containing a space-delimited list of names
138# > that are deleted from the enum class at runtime. Type checkers may
139# > support this mechanism
143 _ignore_ = "DOG FISH"
144 CAT = 1 # Member attribute
145 DOG = 2 # temporary variable, will be removed from the final enum class
146 FISH = 3 # temporary variable, will be removed from the final enum class
149assert_type(Pet5.CAT, Literal[Pet5.CAT])
150assert_type(Pet5.DOG, int) # E?: Literal[2] is also acceptable
151assert_type(Pet5.FISH, int) # E?: Literal[3] is also acceptable