Skip to content
Merged
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
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ Release date: TBA

Closes pylint-dev/pylint#8802


* Fix false positives for ``no-member`` and ``invalid-name`` when using the ``_name_``, ``_value_`` and ``_ignore_`` sunders in Enums.

Closes pylint-dev/pylint#9015

* Fix inference of functions with ``@functools.lru_cache`` decorators without
parentheses.

Expand Down
11 changes: 10 additions & 1 deletion astroid/brain/brain_namedtuple_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,10 @@ def infer_enum_class(node: nodes.ClassDef) -> nodes.ClassDef:
dunder_members = {}
target_names = set()
for local, values in node.locals.items():
if any(not isinstance(value, nodes.AssignName) for value in values):
if (
any(not isinstance(value, nodes.AssignName) for value in values)
or local == "_ignore_"
):
continue

stmt = values[0].statement()
Expand Down Expand Up @@ -440,8 +443,14 @@ class {name}({types}):
def value(self):
return {return_value}
@property
def _value_(self):
return {return_value}
@property
def name(self):
return "{name}"
@property
def _name_(self):
return "{name}"
""".format(
name=target.name,
types=", ".join(node.basenames),
Expand Down
42 changes: 42 additions & 0 deletions tests/brain/test_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,3 +521,45 @@ def __init__(self, mass, radius):
mars, radius = enum_members.items
assert mars[1].name == "MARS"
assert radius[1].name == "radius"

def test_enum_with_ignore(self) -> None:
"""Exclude ``_ignore_`` from the ``__members__`` container
Originally reported in https://github.com/pylint-dev/pylint/issues/9015
"""

ast_node: nodes.Attribute = builder.extract_node(
"""
import enum


class MyEnum(enum.Enum):
FOO = enum.auto()
BAR = enum.auto()
_ignore_ = ["BAZ"]
BAZ = 42
MyEnum.__members__
"""
)
inferred = next(ast_node.infer())
members_names = [const_node.value for const_node, name_obj in inferred.items]
assert members_names == ["FOO", "BAR", "BAZ"]

def test_enum_sunder_names(self) -> None:
"""Test that both `_name_` and `_value_` sunder names exist"""

sunder_name, sunder_value = builder.extract_node(
"""
import enum


class MyEnum(enum.Enum):
APPLE = 42
MyEnum.APPLE._name_ #@
MyEnum.APPLE._value_ #@
"""
)
inferred_name = next(sunder_name.infer())
assert inferred_name.value == "APPLE"

inferred_value = next(sunder_value.infer())
assert inferred_value.value == 42