Skip to content

Commit 412c03a

Browse files
committed
Do not treat unassigned attributes as enum members
1 parent 6c5b13c commit 412c03a

File tree

4 files changed

+25
-2
lines changed

4 files changed

+25
-2
lines changed

mypy/checkmember.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,7 @@ def apply_class_attr_hook(
13421342
def analyze_enum_class_attribute_access(
13431343
itype: Instance, name: str, mx: MemberContext
13441344
) -> Type | None:
1345+
# This function should be kept in sync with TypeInfo.enum_members
13451346
# Skip these since Enum will remove it
13461347
if name in EXCLUDED_ENUM_ATTRIBUTES:
13471348
return report_missing_attribute(mx.original_type, itype, name, mx)
@@ -1350,6 +1351,9 @@ def analyze_enum_class_attribute_access(
13501351
return None
13511352

13521353
node = itype.type.get(name)
1354+
if not isinstance(node.node, Var) or not node.node.has_explicit_value:
1355+
# Annotated but not assigned attributes are not enum members
1356+
return None
13531357
if node and node.type:
13541358
proper = get_proper_type(node.type)
13551359
# Support `A = nonmember(1)` function call and decorator.

mypy/nodes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3317,6 +3317,7 @@ def protocol_members(self) -> list[str]:
33173317

33183318
@property
33193319
def enum_members(self) -> list[str]:
3320+
# This method should be kept in sync with checkmember.analyze_enum_class_attribute_access
33203321
# TODO: cache the results?
33213322
members = []
33223323
for name, sym in self.names.items():

mypy/typeanal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ def analyze_unbound_type_without_type_info(
959959
isinstance(sym.node, Var)
960960
and sym.node.info
961961
and sym.node.info.is_enum
962-
and not sym.node.name.startswith("__")
962+
and sym.node.name in sym.node.info.enum_members
963963
):
964964
value = sym.node.name
965965
base_enum_short_name = sym.node.info.name

test-data/unit/check-enum.test

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,8 @@ class F(Generic[T], Enum): # E: Enum class cannot be generic
457457
x: T
458458
y: T
459459

460-
reveal_type(F[int].x) # N: Revealed type is "__main__.F[builtins.int]"
460+
reveal_type(F[int].x) # E: Access to generic instance variables via class is ambiguous \
461+
# N: Revealed type is "builtins.int"
461462
[builtins fixtures/enum.pyi]
462463

463464
[case testEnumFlag]
@@ -1422,6 +1423,23 @@ class Comparator(enum.Enum):
14221423
reveal_type(Comparator.__foo__) # N: Revealed type is "builtins.dict[builtins.str, builtins.int]"
14231424
[builtins fixtures/dict.pyi]
14241425

1426+
[case testEnumClassAttributeUnannotated]
1427+
import enum
1428+
from typing import ClassVar, Literal
1429+
1430+
class MyEnum(enum.Enum):
1431+
foo: ClassVar[str]
1432+
bar: str
1433+
1434+
VALUE_A = 1
1435+
VALUE_B = 2
1436+
1437+
reveal_type(MyEnum.foo) # N: Revealed type is "builtins.str"
1438+
reveal_type(MyEnum.bar) # N: Revealed type is "builtins.str"
1439+
x: Literal[MyEnum.foo] # E: Parameter 1 of Literal[...] is invalid
1440+
y: Literal[MyEnum.bar] # E: Parameter 1 of Literal[...] is invalid
1441+
[builtins fixtures/enum.pyi]
1442+
14251443
[case testEnumWithInstanceAttributes]
14261444
from enum import Enum
14271445
class Foo(Enum):

0 commit comments

Comments
 (0)