Skip to content

Commit 0320b79

Browse files
committed
Correctly infer x: SomeEnum; x.name as union of literal names
1 parent e37d92d commit 0320b79

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

mypy/plugins/enums.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,26 @@ def enum_name_callback(ctx: mypy.plugin.AttributeContext) -> Type:
5454
This plugin assumes that the provided context is an attribute access
5555
matching one of the strings found in 'ENUM_NAME_ACCESS'.
5656
"""
57+
# This might be `SomeEnum.Field.name` case:
5758
enum_field_name = _extract_underlying_field_name(ctx.type)
58-
if enum_field_name is None:
59-
return ctx.default_attr_type
60-
else:
59+
if enum_field_name is not None:
6160
str_type = ctx.api.named_generic_type("builtins.str", [])
6261
literal_type = LiteralType(enum_field_name, fallback=str_type)
6362
return str_type.copy_modified(last_known_value=literal_type)
6463

64+
# Or `field: SomeEnum = SomeEnum.field; field.name` case:
65+
if not isinstance(ctx.type, Instance) or not ctx.type.type.is_enum:
66+
return ctx.default_attr_type
67+
enum_names = ctx.type.type.enum_members
68+
if enum_names:
69+
str_type = ctx.api.named_generic_type("builtins.str", [])
70+
return make_simplified_union([
71+
LiteralType(enum_name, fallback=str_type)
72+
for enum_name in enum_names
73+
])
74+
75+
return ctx.default_attr_type
76+
6577

6678
_T = TypeVar("_T")
6779

test-data/unit/check-enum.test

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,38 @@ reveal_type(Truth.true.name) # N: Revealed type is "Literal['true']?"
9494
reveal_type(Truth.false.value) # N: Revealed type is "Literal[False]?"
9595
[builtins fixtures/bool.pyi]
9696

97+
[case testEnumNameValueOnType]
98+
from enum import Enum, Flag, IntEnum, member, nonmember
99+
class Colors(Enum):
100+
red = 1
101+
blue = 2
102+
green = 3
103+
white = nonmember(0)
104+
x: Colors = Colors.red
105+
reveal_type(x.name) # N: Revealed type is "Union[Literal['red'], Literal['blue'], Literal['green']]"
106+
107+
class Numbers(IntEnum):
108+
one = 1
109+
two = 2
110+
three = 3
111+
_magic_ = member(4)
112+
y: Numbers = Numbers.one
113+
reveal_type(y.name) # N: Revealed type is "Union[Literal['one'], Literal['two'], Literal['three'], Literal['_magic_']]"
114+
115+
class Flags(Flag):
116+
en = "en"
117+
us = "us"
118+
@member
119+
def all(self) -> str:
120+
return "all"
121+
z: Flags = Flags.en
122+
reveal_type(z.name) # N: Revealed type is "Union[Literal['en'], Literal['us'], Literal['all']]"
123+
124+
class Empty(Enum): ...
125+
e: Empty
126+
reveal_type(e.name) # N: Revealed type is "builtins.str"
127+
[builtins fixtures/tuple.pyi]
128+
97129
[case testEnumValueExtended]
98130
from enum import Enum
99131
class Truth(Enum):

0 commit comments

Comments
 (0)