Skip to content

Commit

Permalink
Prevent a recursion error to happen when inferring the declared metac…
Browse files Browse the repository at this point in the history
…lass of a class

Close #749
  • Loading branch information
PCManticore committed Mar 7, 2020
1 parent 04f5853 commit 00bcf7b
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 1 deletion.
4 changes: 4 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ Release Date: TBA

Close PyCQA/pylint#3417

* Prevent a recursion error to happen when inferring the declared metaclass of a class

Close #749

* Raise ``AttributeInferenceError`` when ``getattr()`` receives an empty name

Close PyCQA/pylint#2991
Expand Down
3 changes: 2 additions & 1 deletion astroid/scoped_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2456,7 +2456,8 @@ def _metaclass_lookup_attribute(self, name, context):
"""Search the given name in the implicit and the explicit metaclass."""
attrs = set()
implicit_meta = self.implicit_metaclass()
metaclass = self.metaclass()
context = contextmod.copy_context(context)
metaclass = self.metaclass(context=context)
for cls in {implicit_meta, metaclass}:
if cls and cls != self and isinstance(cls, ClassDef):
cls_attributes = self._get_attribute_from_metaclass(cls, name, context)
Expand Down
Empty file.
17 changes: 17 additions & 0 deletions tests/testdata/python3/data/metaclass_recursion/monkeypatch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# https://github.com/PyCQA/astroid/issues/749
# Not an actual module but allows us to reproduce the issue
from tests.testdata.python3.data.metaclass_recursion import parent

class MonkeyPatchClass(parent.OriginalClass):
_original_class = parent.OriginalClass

@classmethod
def patch(cls):
if parent.OriginalClass != MonkeyPatchClass:
cls._original_class = parent.OriginalClass
parent.OriginalClass = MonkeyPatchClass

@classmethod
def unpatch(cls):
if parent.OriginalClass == MonkeyPatchClass:
parent.OriginalClass = cls._original_class
3 changes: 3 additions & 0 deletions tests/testdata/python3/data/metaclass_recursion/parent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://github.com/PyCQA/astroid/issues/749
class OriginalClass:
pass
9 changes: 9 additions & 0 deletions tests/unittest_inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -5755,5 +5755,14 @@ def test(args):
assert inferred is util.Uninferable


def test_recursion_error_metaclass_monkeypatching():
module = resources.build_file(
"data/metaclass_recursion/monkeypatch.py", "data.metaclass_recursion"
)
cls = next(module.igetattr("MonkeyPatchClass"))
assert isinstance(cls, nodes.ClassDef)
assert cls.declared_metaclass() is None


if __name__ == "__main__":
unittest.main()

0 comments on commit 00bcf7b

Please sign in to comment.