diff options
| author | Stanislav Levin <slev@altlinux.org> | 2019-12-22 23:08:47 +0300 |
|---|---|---|
| committer | Claudiu Popa <pcmanticore@gmail.com> | 2019-12-23 15:23:57 +0100 |
| commit | c54af820fcbaa1dd7a4644670b58a40b4f587ff9 (patch) | |
| tree | b3be93ceed60d9abe02c0ca7aa3e2135d4a995d6 | |
| parent | 1cce2085b06b2147d7da3fdfa53e578cd3278146 (diff) | |
| download | astroid-git-c54af820fcbaa1dd7a4644670b58a40b4f587ff9.tar.gz | |
Make use of cache while transform builtin containers
As of now, the transformation of builtin containers which
members, in turn, are containers relies on `safe_infer`
helper. `safe_infer` tries to infer the node to get its
values. Doing this without a cache containing a previously
inferred nodes lead to infinite recursion, for example, on
resolving a class attribute.
Note: this doesn't help to infer a class attribute by itself
is such a case, but prevents crash.
Closes: https://github.com/PyCQA/pylint/issues/3245
Signed-off-by: Stanislav Levin <slev@altlinux.org>
| -rw-r--r-- | astroid/brain/brain_builtin_inference.py | 9 | ||||
| -rw-r--r-- | tests/unittest_inference.py | 14 |
2 files changed, 20 insertions, 3 deletions
diff --git a/astroid/brain/brain_builtin_inference.py b/astroid/brain/brain_builtin_inference.py index 7cc6095f..3cbe48f7 100644 --- a/astroid/brain/brain_builtin_inference.py +++ b/astroid/brain/brain_builtin_inference.py @@ -154,7 +154,7 @@ def _container_generic_inference(node, context, node_type, transform): if len(node.args) > 1: raise UseInferenceDefault() - arg, = args + (arg,) = args transformed = transform(arg) if not transformed: try: @@ -169,7 +169,7 @@ def _container_generic_inference(node, context, node_type, transform): return transformed -def _container_generic_transform(arg, klass, iterables, build_elts): +def _container_generic_transform(arg, context, klass, iterables, build_elts): if isinstance(arg, klass): return arg elif isinstance(arg, iterables): @@ -177,7 +177,9 @@ def _container_generic_transform(arg, klass, iterables, build_elts): elts = [elt.value for elt in arg.elts] else: # TODO: Does not handle deduplication for sets. - elts = filter(None, map(helpers.safe_infer, arg.elts)) + elts = filter( + None, map(partial(helpers.safe_infer, context=context), arg.elts) + ) elif isinstance(arg, nodes.Dict): # Dicts need to have consts as strings already. if not all(isinstance(elt[0], nodes.Const) for elt in arg.items): @@ -197,6 +199,7 @@ def _infer_builtin_container( ): transform_func = partial( _container_generic_transform, + context=context, klass=klass, iterables=iterables, build_elts=build_elts, diff --git a/tests/unittest_inference.py b/tests/unittest_inference.py index a54c4ee1..a5ed96b1 100644 --- a/tests/unittest_inference.py +++ b/tests/unittest_inference.py @@ -5502,5 +5502,19 @@ def test_property_callable_inference(): assert inferred.value == 42 +def test_recursion_error_inferring_builtin_containers(): + node = extract_node( + """ + class Foo: + a = "foo" + inst = Foo() + + b = tuple([inst.a]) #@ + inst.a = b + """ + ) + helpers.safe_infer(node.targets[0]) + + if __name__ == "__main__": unittest.main() |
