From df308707ce917d377ec9812fedef96691d69dce7 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Fri, 9 Jun 2023 12:10:22 -0400 Subject: [PATCH] Make ``igetattr()`` idempotent This addresses some reports of varying results when running pylint with ``--jobs. The original inconsistency was due to a performance optimization in 2d7a87b, but we have no source for the original bug report it targeted. --- ChangeLog | 6 ++++++ astroid/bases.py | 8 -------- tests/test_inference.py | 16 +++++++++++++++- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 22fce54883..021b376fdf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,12 @@ Release date: TBA * Reduce file system access in ``ast_from_file()``. +* Make ``igetattr()`` idempotent. This addresses some reports of varying results + when running pylint with ``--jobs``. + + Closes pylint-dev/pylint#4356 + Refs #7 + * Fix incorrect cache keys for inference results, thereby correctly inferring types for calls instantiating types dynamically. diff --git a/astroid/bases.py b/astroid/bases.py index 6f3f79c313..8d07ae665a 100644 --- a/astroid/bases.py +++ b/astroid/bases.py @@ -277,14 +277,6 @@ def igetattr( context = InferenceContext() try: context.lookupname = name - # avoid recursively inferring the same attr on the same class - if context.push(self._proxied): - raise InferenceError( - message="Cannot infer the same attribute again", - node=self, - context=context, - ) - # XXX frame should be self._proxied, or not ? get_attr = self.getattr(name, context, lookupclass=False) yield from _infer_stmts( diff --git a/tests/test_inference.py b/tests/test_inference.py index 868c83bc5f..49e85c4168 100644 --- a/tests/test_inference.py +++ b/tests/test_inference.py @@ -4024,7 +4024,7 @@ def __getitem__(self, name): flow['app']['config']['doffing'] = AttributeDict() #@ """ ) - self.assertIsNone(helpers.safe_infer(ast_node.targets[0])) + self.assertIsInstance(helpers.safe_infer(ast_node.targets[0]), Instance) def test_classmethod_inferred_by_context(self) -> None: ast_node = extract_node( @@ -6120,6 +6120,20 @@ def __exit__(self, ex_type, ex_value, ex_tb): next(node.infer()) +def test_igetattr_idempotent() -> None: + code = """ + class InferMeTwice: + item = 10 + + InferMeTwice() + """ + call = extract_node(code) + instance = call.inferred()[0] + context_to_be_used_twice = InferenceContext() + assert util.Uninferable not in instance.igetattr("item", context_to_be_used_twice) + assert util.Uninferable not in instance.igetattr("item", context_to_be_used_twice) + + def test_infer_context_manager_with_unknown_args() -> None: code = """ class client_log(object):