Skip to content

Commit

Permalink
Add InferenceContext to ClassModel (#1257)
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielNoord committed Nov 19, 2021
1 parent b07eb62 commit 96ca4dc
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 2 deletions.
4 changes: 4 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ What's New in astroid 2.8.6?
============================
Release date: TBA

* Fix crash on inference of subclasses created from ``Class().__subclasses__``

Closes PyCQA/pylint#4982

* Fix bug with Python 3.7.0 / 3.7.1 and ``typing.NoReturn``.

Closes #1239
Expand Down
8 changes: 7 additions & 1 deletion astroid/interpreter/objectmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,12 @@ def attr___ne__(self):


class ClassModel(ObjectModel):
def __init__(self):
# Add a context so that inferences called from an instance don't recurse endlessly
self.context = InferenceContext()

super().__init__()

@property
def attr___module__(self):
return node_classes.Const(self._instance.root().qname())
Expand Down Expand Up @@ -485,7 +491,7 @@ def attr___subclasses__(self):
classes = [
cls
for cls in root.nodes_of_class(scoped_nodes.ClassDef)
if cls != self._instance and cls.is_subtype_of(qname)
if cls != self._instance and cls.is_subtype_of(qname, context=self.context)
]

obj = node_classes.List(parent=self._instance)
Expand Down
22 changes: 21 additions & 1 deletion tests/unittest_regrtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

import pytest

from astroid import MANAGER, Instance, nodes, test_utils
from astroid import MANAGER, Instance, nodes, parse, test_utils
from astroid.builder import AstroidBuilder, extract_node
from astroid.const import PY38_PLUS
from astroid.exceptions import InferenceError
Expand Down Expand Up @@ -379,5 +379,25 @@ def fu(self, objects):
assert inferred.qname() == "builtins.dict.__delitem__"


def test_regression_crash_classmethod() -> None:
"""Regression test for a crash reported in https://github.com/PyCQA/pylint/issues/4982"""
code = """
class Base:
@classmethod
def get_first_subclass(cls):
for subclass in cls.__subclasses__():
return subclass
return object
subclass = Base.get_first_subclass()
class Another(subclass):
pass
"""
parse(code)


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

0 comments on commit 96ca4dc

Please sign in to comment.