Skip to content

Commit 87d1569

Browse files
committed
Fixes enum value inference in cases where the value type is of a
user-defined data type class (with __new__). This fixes a regression introduced by python#10057 to fix python#10000. The `not ti.fullname.startswith("builtins.") clause seemed to be intended to catch enums with a built-in data type like int or bytes, but this is overly broad. It should allow any type so long as it is not itself an enum.Enum subclass.
1 parent 8236c93 commit 87d1569

File tree

2 files changed

+20
-2
lines changed

2 files changed

+20
-2
lines changed

mypy/plugins/enums.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,17 @@ def _infer_value_type_with_auto_fallback(
104104

105105
def _implements_new(info: TypeInfo) -> bool:
106106
"""Check whether __new__ comes from enum.Enum or was implemented in a
107-
subclass. In the latter case, we must infer Any as long as mypy can't infer
107+
subclass of enum.Enum. In the latter case, we must infer Any as long as mypy can't infer
108108
the type of _value_ from assignments in __new__.
109+
110+
If, however, __new__ comes from a user-defined class that is not an Enum subclass (i.e.
111+
the data type) this is allowed, because we should in general infer that an enum entry's
112+
value has that type.
109113
"""
110114
type_with_new = _first(
111115
ti
112116
for ti in info.mro
113-
if ti.names.get("__new__") and not ti.fullname.startswith("builtins.")
117+
if ti.is_enum and ti.names.get("__new__")
114118
)
115119
if type_with_new is None:
116120
return False

test-data/unit/check-enum.test

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,20 @@ reveal_type(a._value_) # N: Revealed type is "Any"
13661366
[builtins fixtures/primitives.pyi]
13671367
[typing fixtures/typing-medium.pyi]
13681368

1369+
[case testValueTypeWithUserDataType]
1370+
from enum import Enum
1371+
from typing import Any
1372+
1373+
class Data:
1374+
def __new__(cls, value: Any) -> Data: pass
1375+
1376+
class DataEnum(Data, Enum):
1377+
A = Data(1)
1378+
1379+
reveal_type(DataEnum.A) # N: Revealed type is "Literal[__main__.DataEnum.A]?"
1380+
reveal_type(DataEnum.A.value) # N: Revealed type is "__main__.Data"
1381+
reveal_type(DataEnum.A._value_) # N: Revealed type is "__main__.Data"
1382+
13691383
[case testEnumNarrowedToTwoLiterals]
13701384
# Regression test: two literals of an enum would be joined
13711385
# as the full type, regardless of the amount of elements

0 commit comments

Comments
 (0)