Skip to content

Commit 01a0a7a

Browse files
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: pylint-dev/pylint#3245 Signed-off-by: Stanislav Levin <[email protected]>
1 parent 1cce208 commit 01a0a7a

File tree

2 files changed

+20
-3
lines changed

2 files changed

+20
-3
lines changed

astroid/brain/brain_builtin_inference.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ def _container_generic_inference(node, context, node_type, transform):
154154
if len(node.args) > 1:
155155
raise UseInferenceDefault()
156156

157-
arg, = args
157+
(arg,) = args
158158
transformed = transform(arg)
159159
if not transformed:
160160
try:
@@ -169,15 +169,17 @@ def _container_generic_inference(node, context, node_type, transform):
169169
return transformed
170170

171171

172-
def _container_generic_transform(arg, klass, iterables, build_elts):
172+
def _container_generic_transform(arg, context, klass, iterables, build_elts):
173173
if isinstance(arg, klass):
174174
return arg
175175
elif isinstance(arg, iterables):
176176
if all(isinstance(elt, nodes.Const) for elt in arg.elts):
177177
elts = [elt.value for elt in arg.elts]
178178
else:
179179
# TODO: Does not handle deduplication for sets.
180-
elts = filter(None, map(helpers.safe_infer, arg.elts))
180+
elts = filter(
181+
None, map(partial(helpers.safe_infer, context=context), arg.elts)
182+
)
181183
elif isinstance(arg, nodes.Dict):
182184
# Dicts need to have consts as strings already.
183185
if not all(isinstance(elt[0], nodes.Const) for elt in arg.items):
@@ -197,6 +199,7 @@ def _infer_builtin_container(
197199
):
198200
transform_func = partial(
199201
_container_generic_transform,
202+
context=context,
200203
klass=klass,
201204
iterables=iterables,
202205
build_elts=build_elts,

tests/unittest_inference.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5502,5 +5502,19 @@ class A:
55025502
assert inferred.value == 42
55035503

55045504

5505+
def test_recursion_error_inferring_builtin_containers():
5506+
node = extract_node(
5507+
"""
5508+
class Foo:
5509+
a = "foo"
5510+
inst = Foo()
5511+
5512+
b = tuple([inst.a]) #@
5513+
inst.a = b
5514+
"""
5515+
)
5516+
helpers.safe_infer(node.targets[0])
5517+
5518+
55055519
if __name__ == "__main__":
55065520
unittest.main()

0 commit comments

Comments
 (0)