Skip to content

Commit 43b7f9a

Browse files
authored
Exclude the _ignore_ attribute from the __members__ container. (#2289)
Refs pylint-dev/pylint#9015 * Fix a false positive for ``no-member`` when accessing the ``_name_`` and ``_value_`` sunders of an Enum member value. Refs pylint-dev/pylint#7402
1 parent 2288d7f commit 43b7f9a

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

ChangeLog

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ Release date: TBA
221221

222222
Closes pylint-dev/pylint#8802
223223

224+
225+
* Fix false positives for ``no-member`` and ``invalid-name`` when using the ``_name_``, ``_value_`` and ``_ignore_`` sunders in Enums.
226+
227+
Closes pylint-dev/pylint#9015
228+
224229
* Fix inference of functions with ``@functools.lru_cache`` decorators without
225230
parentheses.
226231

astroid/brain/brain_namedtuple_enum.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,10 @@ def infer_enum_class(node: nodes.ClassDef) -> nodes.ClassDef:
403403
dunder_members = {}
404404
target_names = set()
405405
for local, values in node.locals.items():
406-
if any(not isinstance(value, nodes.AssignName) for value in values):
406+
if (
407+
any(not isinstance(value, nodes.AssignName) for value in values)
408+
or local == "_ignore_"
409+
):
407410
continue
408411

409412
stmt = values[0].statement()
@@ -440,8 +443,14 @@ class {name}({types}):
440443
def value(self):
441444
return {return_value}
442445
@property
446+
def _value_(self):
447+
return {return_value}
448+
@property
443449
def name(self):
444450
return "{name}"
451+
@property
452+
def _name_(self):
453+
return "{name}"
445454
""".format(
446455
name=target.name,
447456
types=", ".join(node.basenames),

tests/brain/test_enum.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,3 +521,45 @@ def __init__(self, mass, radius):
521521
mars, radius = enum_members.items
522522
assert mars[1].name == "MARS"
523523
assert radius[1].name == "radius"
524+
525+
def test_enum_with_ignore(self) -> None:
526+
"""Exclude ``_ignore_`` from the ``__members__`` container
527+
Originally reported in https://github.com/pylint-dev/pylint/issues/9015
528+
"""
529+
530+
ast_node: nodes.Attribute = builder.extract_node(
531+
"""
532+
import enum
533+
534+
535+
class MyEnum(enum.Enum):
536+
FOO = enum.auto()
537+
BAR = enum.auto()
538+
_ignore_ = ["BAZ"]
539+
BAZ = 42
540+
MyEnum.__members__
541+
"""
542+
)
543+
inferred = next(ast_node.infer())
544+
members_names = [const_node.value for const_node, name_obj in inferred.items]
545+
assert members_names == ["FOO", "BAR", "BAZ"]
546+
547+
def test_enum_sunder_names(self) -> None:
548+
"""Test that both `_name_` and `_value_` sunder names exist"""
549+
550+
sunder_name, sunder_value = builder.extract_node(
551+
"""
552+
import enum
553+
554+
555+
class MyEnum(enum.Enum):
556+
APPLE = 42
557+
MyEnum.APPLE._name_ #@
558+
MyEnum.APPLE._value_ #@
559+
"""
560+
)
561+
inferred_name = next(sunder_name.infer())
562+
assert inferred_name.value == "APPLE"
563+
564+
inferred_value = next(sunder_value.infer())
565+
assert inferred_value.value == 42

0 commit comments

Comments
 (0)