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):