diff --git a/ChangeLog b/ChangeLog index be41c4012..9d18e3eb4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -41,6 +41,13 @@ Release date: TBA References pylint-dev/pylint#872 +* Fix ``DuplicateBasesError`` crash in the enum brain when inferring an enum + class with duplicate bases (e.g. ``class C(enum.Enum, enum.Enum)``). + ``infer_enum_class`` now catches ``MroError`` and leaves such a malformed + class untransformed. + + Closes #3065 + What's New in astroid 4.1.2? ============================ diff --git a/astroid/brain/brain_namedtuple_enum.py b/astroid/brain/brain_namedtuple_enum.py index dfd8ccf9d..a51d9a2fb 100644 --- a/astroid/brain/brain_namedtuple_enum.py +++ b/astroid/brain/brain_namedtuple_enum.py @@ -19,6 +19,7 @@ AstroidTypeError, AstroidValueError, InferenceError, + MroError, UseInferenceDefault, ) from astroid.inference_tip import inference_tip @@ -386,7 +387,13 @@ def __mul__(self, other): def infer_enum_class(node: nodes.ClassDef) -> nodes.ClassDef: """Specific inference for enums.""" - for basename in (b for cls in node.mro() for b in cls.basenames): + try: + mro = node.mro() + except MroError: + # A malformed class hierarchy (e.g. duplicate bases) has no resolvable + # MRO; leave the node untransformed rather than crashing. + return node + for basename in (b for cls in mro for b in cls.basenames): if node.root().name == "enum": # Skip if the class is directly from enum module. break diff --git a/tests/brain/test_enum.py b/tests/brain/test_enum.py index 7c9afee84..1fc5c80d2 100644 --- a/tests/brain/test_enum.py +++ b/tests/brain/test_enum.py @@ -559,3 +559,18 @@ class MyEnum(enum.Enum): inferred_value = next(sunder_value.infer()) assert inferred_value.value == 42 + + def test_enum_duplicate_bases_no_crash(self) -> None: + """An enum class with duplicate bases has no resolvable MRO. + + Regression test for https://github.com/pylint-dev/astroid/issues/3065 + """ + node = builder.extract_node(""" + import enum + + class C(enum.Enum, enum.Enum): #@ + pass + """) + # Inference must not raise ``DuplicateBasesError``. + inferred = next(node.infer()) + assert isinstance(inferred, nodes.ClassDef)