summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--astroid/brain/brain_six.py1
-rw-r--r--astroid/nodes/scoped_nodes/scoped_nodes.py10
-rw-r--r--tests/brain/test_six.py5
-rw-r--r--tests/test_scoped_nodes.py14
5 files changed, 31 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index b0182157..8f3ac7d9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -12,6 +12,12 @@ What's New in astroid 2.15.1?
=============================
Release date: TBA
+* Restore behavior of setting a Call as a base for classes created using ``six.with_metaclass()``,
+ and harden support for using enums as metaclasses in this case.
+
+ Reverts #1622
+ Refs PyCQA/pylint#5935
+ Refs PyCQA/pylint#7506
What's New in astroid 2.15.0?
diff --git a/astroid/brain/brain_six.py b/astroid/brain/brain_six.py
index a35cfdd6..0eb945d8 100644
--- a/astroid/brain/brain_six.py
+++ b/astroid/brain/brain_six.py
@@ -219,7 +219,6 @@ def transform_six_with_metaclass(node):
"""
call = node.bases[0]
node._metaclass = call.args[0]
- node.bases = call.args[1:]
return node
diff --git a/astroid/nodes/scoped_nodes/scoped_nodes.py b/astroid/nodes/scoped_nodes/scoped_nodes.py
index bec817d7..530d9e6d 100644
--- a/astroid/nodes/scoped_nodes/scoped_nodes.py
+++ b/astroid/nodes/scoped_nodes/scoped_nodes.py
@@ -1703,7 +1703,15 @@ class FunctionDef(_base_nodes.MultiLineBlockNode, _base_nodes.Statement, Lambda)
metaclass = next(caller.args[0].infer(context), None)
if isinstance(metaclass, ClassDef):
try:
- class_bases = [next(arg.infer(context)) for arg in caller.args[1:]]
+ class_bases = [
+ # Find the first non-None inferred base value
+ next(
+ b
+ for b in arg.infer(context=context.clone())
+ if not (isinstance(b, Const) and b.value is None)
+ )
+ for arg in caller.args[1:]
+ ]
except StopIteration as e:
raise InferenceError(node=caller.args[1:], context=context) from e
new_class = ClassDef(name="temporary_class")
diff --git a/tests/brain/test_six.py b/tests/brain/test_six.py
index 1ff184d3..c9dac562 100644
--- a/tests/brain/test_six.py
+++ b/tests/brain/test_six.py
@@ -110,8 +110,7 @@ class SixBrainTest(unittest.TestCase):
inferred = next(ast_node.infer())
self.assertIsInstance(inferred, nodes.ClassDef)
self.assertEqual(inferred.name, "B")
- self.assertIsInstance(inferred.bases[0], nodes.Name)
- self.assertEqual(inferred.bases[0].name, "C")
+ self.assertIsInstance(inferred.bases[0], nodes.Call)
ancestors = tuple(inferred.ancestors())
self.assertIsInstance(ancestors[0], nodes.ClassDef)
self.assertEqual(ancestors[0].name, "C")
@@ -131,7 +130,7 @@ class SixBrainTest(unittest.TestCase):
bar = 1
"""
klass = astroid.extract_node(code)
- assert list(klass.ancestors())[-1].name == "Enum"
+ assert next(klass.ancestors()).name == "Enum"
def test_six_with_metaclass_with_additional_transform(self) -> None:
def transform_class(cls: Any) -> ClassDef:
diff --git a/tests/test_scoped_nodes.py b/tests/test_scoped_nodes.py
index a69983c6..2722c56f 100644
--- a/tests/test_scoped_nodes.py
+++ b/tests/test_scoped_nodes.py
@@ -1403,6 +1403,20 @@ class ClassNodeTest(ModuleLoader, unittest.TestCase):
self.assertEqual(["object"], [base.name for base in klass.ancestors()])
self.assertEqual("type", klass.metaclass().name)
+ @unittest.skipUnless(HAS_SIX, "These tests require the six library")
+ def test_metaclass_generator_hack_enum_base(self):
+ """Regression test for https://github.com/PyCQA/pylint/issues/5935"""
+ klass = builder.extract_node(
+ """
+ import six
+ from enum import Enum, EnumMeta
+
+ class PetEnumPy2Metaclass(six.with_metaclass(EnumMeta, Enum)): #@
+ DOG = "dog"
+ """
+ )
+ self.assertEqual(list(klass.local_attr_ancestors("DOG")), [])
+
def test_add_metaclass(self) -> None:
klass = builder.extract_node(
"""