aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniƫl van Noord <13665637+DanielNoord@users.noreply.github.com>2021-11-08 13:25:14 +0200
committerGitHub <noreply@github.com>2021-11-08 12:25:14 +0100
commite1ecb6d3d5a6555a807ab3db0f2f938d8d73e95c (patch)
treeec71ec435466dca43936f5418a3c9663bc2e0e6a
parentb62f243b16b7f435c8be869577959e95a7927a91 (diff)
downloadastroid-e1ecb6d3d5a6555a807ab3db0f2f938d8d73e95c.tar.gz
Fix crash on inference of __len__ (#1234)
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
-rw-r--r--ChangeLog4
-rw-r--r--astroid/helpers.py2
-rw-r--r--tests/unittest_brain.py53
3 files changed, 58 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index baf3638f..4c098507 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -12,6 +12,10 @@ What's New in astroid 2.8.5?
============================
Release date: TBA
+* Fix crash on inference of ``__len__``.
+
+ Closes PyCQA/pylint#5244
+
* Added missing ``kind`` (for ``Const``) and ``conversion`` (for ``FormattedValue``) fields to repr.
diff --git a/astroid/helpers.py b/astroid/helpers.py
index 567b2e04..32fb796e 100644
--- a/astroid/helpers.py
+++ b/astroid/helpers.py
@@ -258,7 +258,7 @@ def object_len(node, context=None):
if (
isinstance(node_frame, scoped_nodes.FunctionDef)
and node_frame.name == "__len__"
- and inferred_node is not None
+ and hasattr(inferred_node, "_proxied")
and inferred_node._proxied == node_frame.parent
):
message = (
diff --git a/tests/unittest_brain.py b/tests/unittest_brain.py
index d3bf12bc..a33647fe 100644
--- a/tests/unittest_brain.py
+++ b/tests/unittest_brain.py
@@ -3112,6 +3112,8 @@ def test_str_and_bytes(code, expected_class, expected_value):
def test_no_recursionerror_on_self_referential_length_check() -> None:
"""
Regression test for https://github.com/PyCQA/astroid/issues/777
+
+ This test should only raise an InferenceError and no RecursionError.
"""
with pytest.raises(InferenceError):
node = astroid.extract_node(
@@ -3126,5 +3128,56 @@ def test_no_recursionerror_on_self_referential_length_check() -> None:
node.inferred()
+def test_inference_on_outer_referential_length_check() -> None:
+ """
+ Regression test for https://github.com/PyCQA/pylint/issues/5244
+ See also https://github.com/PyCQA/astroid/pull/1234
+
+ This test should succeed without any error.
+ """
+ node = astroid.extract_node(
+ """
+ class A:
+ def __len__(self) -> int:
+ return 42
+
+ class Crash:
+ def __len__(self) -> int:
+ a = A()
+ return len(a)
+
+ len(Crash()) #@
+ """
+ )
+ inferred = node.inferred()
+ assert len(inferred) == 1
+ assert isinstance(inferred[0], nodes.Const)
+ assert inferred[0].value == 42
+
+
+def test_no_attributeerror_on_self_referential_length_check() -> None:
+ """
+ Regression test for https://github.com/PyCQA/pylint/issues/5244
+ See also https://github.com/PyCQA/astroid/pull/1234
+
+ This test should only raise an InferenceError and no AttributeError.
+ """
+ with pytest.raises(InferenceError):
+ node = astroid.extract_node(
+ """
+ class MyClass:
+ def some_func(self):
+ return lambda: 42
+
+ def __len__(self):
+ return len(self.some_func())
+
+ len(MyClass()) #@
+ """
+ )
+ assert isinstance(node, nodes.NodeNG)
+ node.inferred()
+
+
if __name__ == "__main__":
unittest.main()