File tree Expand file tree Collapse file tree 3 files changed +41
-17
lines changed Expand file tree Collapse file tree 3 files changed +41
-17
lines changed Original file line number Diff line number Diff line change @@ -20,6 +20,10 @@ Release date: TBA
20
20
21
21
Closes pylint-dev/pylint#8802
22
22
23
+ * Infer user-defined enum classes by checking if the class is a subtype of ``enum.Enum``.
24
+
25
+ Closes pylint-dev/pylint#8897
26
+
23
27
* Fix inference of functions with ``@functools.lru_cache`` decorators without
24
28
parentheses.
25
29
Original file line number Diff line number Diff line change 20
20
AstroidTypeError ,
21
21
AstroidValueError ,
22
22
InferenceError ,
23
- MroError ,
24
23
UseInferenceDefault ,
25
24
)
26
25
from astroid .manager import AstroidManager
31
30
from typing_extensions import Final
32
31
33
32
34
- ENUM_BASE_NAMES = {
35
- "Enum" ,
36
- "IntEnum" ,
37
- "enum.Enum" ,
38
- "enum.IntEnum" ,
39
- "IntFlag" ,
40
- "enum.IntFlag" ,
41
- }
42
33
ENUM_QNAME : Final [str ] = "enum.Enum"
43
34
TYPING_NAMEDTUPLE_QUALIFIED : Final = {
44
35
"typing.NamedTuple" ,
@@ -606,14 +597,7 @@ def _get_namedtuple_fields(node: nodes.Call) -> str:
606
597
607
598
def _is_enum_subclass (cls : astroid .ClassDef ) -> bool :
608
599
"""Return whether cls is a subclass of an Enum."""
609
- try :
610
- return any (
611
- klass .name in ENUM_BASE_NAMES
612
- and getattr (klass .root (), "name" , None ) == "enum"
613
- for klass in cls .mro ()
614
- )
615
- except MroError :
616
- return False
600
+ return cls .is_subtype_of ("enum.Enum" )
617
601
618
602
619
603
AstroidManager ().register_transform (
Original file line number Diff line number Diff line change @@ -493,3 +493,39 @@ def pear(self):
493
493
for node in (attribute_nodes [1 ], name_nodes [1 ]):
494
494
with pytest .raises (InferenceError ):
495
495
node .inferred ()
496
+
497
+ def test_local_enum_child_class_inference (self ) -> None :
498
+ """Originally reported in https://github.com/pylint-dev/pylint/issues/8897
499
+
500
+ Test that a user-defined enum class is inferred when it subclasses
501
+ another user-defined enum class.
502
+ """
503
+ enum_class_node , enum_member_value_node = astroid .extract_node (
504
+ """
505
+ import sys
506
+
507
+ from enum import Enum
508
+
509
+ if sys.version_info >= (3, 11):
510
+ from enum import StrEnum
511
+ else:
512
+ class StrEnum(str, Enum):
513
+ pass
514
+
515
+
516
+ class Color(StrEnum): #@
517
+ RED = "red"
518
+
519
+
520
+ Color.RED.value #@
521
+ """
522
+ )
523
+ assert "RED" in enum_class_node .locals
524
+
525
+ enum_members = enum_class_node .locals ["__members__" ][0 ].items
526
+ assert len (enum_members ) == 1
527
+ _ , name = enum_members [0 ]
528
+ assert name .name == "RED"
529
+
530
+ inferred_enum_member_value_node = next (enum_member_value_node .infer ())
531
+ assert inferred_enum_member_value_node .value == "red"
You can’t perform that action at this time.
0 commit comments