Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly account for member and nonmember in TypeInfo.enum_members #18559

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions mypy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3235,10 +3235,26 @@ def enum_members(self) -> list[str]:
name
for name, sym in self.names.items()
if (
isinstance(sym.node, Var)
and name not in EXCLUDED_ENUM_ATTRIBUTES
and not name.startswith("__")
and sym.node.has_explicit_value
(
isinstance(sym.node, Var)
and name not in EXCLUDED_ENUM_ATTRIBUTES
and not name.startswith("__")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this condition exist for enum.member too because #18563?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, good question. Let's keep it for now, I will change it in #18563 if needed.

and sym.node.has_explicit_value
and not (
isinstance(
typ := mypy.types.get_proper_type(sym.node.type), mypy.types.Instance
)
and typ.type.fullname == "enum.nonmember"
)
)
or (
isinstance(sym.node, Decorator)
and any(
dec.fullname == "enum.member"
for dec in sym.node.decorators
if isinstance(dec, RefExpr)
)
)
)
]

Expand Down
2 changes: 1 addition & 1 deletion mypy/typeops.py
Original file line number Diff line number Diff line change
Expand Up @@ -955,7 +955,7 @@ class Status(Enum):
FAILURE = 2
UNKNOWN = 3

...and if we call `try_expanding_enum_to_union(Union[Color, Status], 'module.Color')`,
...and if we call `try_expanding_sum_type_to_union(Union[Color, Status], 'module.Color')`,
this function will return Literal[Color.RED, Color.BLUE, Color.YELLOW, Status].
"""
typ = get_proper_type(typ)
Expand Down
34 changes: 34 additions & 0 deletions test-data/unit/check-enum.test
Original file line number Diff line number Diff line change
Expand Up @@ -1938,6 +1938,18 @@ class D(C): # E: Cannot extend enum with existing members: "C" \
x: int # E: Cannot assign to final name "x"
[builtins fixtures/bool.pyi]

[case testEnumNotFinalWithMethodsAndUninitializedValuesStubMember]
# flags: --python-version 3.11
# This was added in 3.11
import lib

[file lib.pyi]
from enum import Enum, member
class A(Enum):
@member
def x(self) -> None: ...
[builtins fixtures/bool.pyi]

[case testEnumLiteralValues]
from enum import Enum

Expand Down Expand Up @@ -2330,6 +2342,28 @@ def some_a(a: A):
[builtins fixtures/dict.pyi]


[case testEnumMemberAndNonMemberSupport]
# flags: --python-version 3.11 --warn-unreachable
# This was added in 3.11
from enum import Enum, member, nonmember

class A(Enum):
x = 1
y = member(2)
z = nonmember(3)

def some_a(a: A):
if a is not A.x and a is not A.z:
reveal_type(a) # N: Revealed type is "Literal[__main__.A.y]"
if a is not A.y and a is not A.z:
reveal_type(a) # N: Revealed type is "Literal[__main__.A.x]"
if a is not A.x:
reveal_type(a) # N: Revealed type is "Literal[__main__.A.y]"
if a is not A.y:
reveal_type(a) # N: Revealed type is "Literal[__main__.A.x]"
[builtins fixtures/dict.pyi]


[case testErrorOnAnnotatedMember]
from enum import Enum

Expand Down
Loading