Skip to content

Commit b26a491

Browse files
Catch the StopIteration that result from PEP-479
StopIteration exceptions raised directly or indirectly in coroutines and generators are transformed into RuntimeError exceptions for python 3.7+.
1 parent 366daef commit b26a491

16 files changed

+155
-82
lines changed

astroid/arguments.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ def _unpack_keywords(self, keywords, context=None):
101101
except InferenceError:
102102
values[name] = util.Uninferable
103103
continue
104+
except StopIteration:
105+
continue
104106

105107
if not isinstance(inferred, nodes.Dict):
106108
# Not something we can work with.
@@ -113,6 +115,8 @@ def _unpack_keywords(self, keywords, context=None):
113115
except InferenceError:
114116
values[name] = util.Uninferable
115117
continue
118+
except StopIteration:
119+
continue
116120
if not isinstance(dict_key, nodes.Const):
117121
values[name] = util.Uninferable
118122
continue
@@ -140,6 +144,8 @@ def _unpack_args(self, args, context=None):
140144
except InferenceError:
141145
values.append(util.Uninferable)
142146
continue
147+
except StopIteration:
148+
continue
143149

144150
if inferred is util.Uninferable:
145151
values.append(util.Uninferable)

astroid/bases.py

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,10 @@ def _infer_method_result_truth(instance, method_name, context):
169169
for value in meth.infer_call_result(instance, context=context):
170170
if value is util.Uninferable:
171171
return value
172-
173-
inferred = next(value.infer(context=context))
172+
try:
173+
inferred = next(value.infer(context=context))
174+
except StopIteration as e:
175+
raise InferenceError(context=context) from e
174176
return inferred.bool_value()
175177
except InferenceError:
176178
pass
@@ -344,7 +346,7 @@ def getitem(self, index, context=None):
344346
node=self,
345347
context=context,
346348
)
347-
return next(method.infer_call_result(self, new_context))
349+
return next(method.infer_call_result(self, new_context), None)
348350

349351

350352
class UnboundMethod(Proxy):
@@ -434,7 +436,10 @@ def _infer_type_new_call(self, caller, context):
434436
from astroid import node_classes
435437

436438
# Verify the metaclass
437-
mcs = next(caller.args[0].infer(context=context))
439+
try:
440+
mcs = next(caller.args[0].infer(context=context))
441+
except StopIteration as e:
442+
raise InferenceError(context=context) from e
438443
if mcs.__class__.__name__ != "ClassDef":
439444
# Not a valid first argument.
440445
return None
@@ -443,7 +448,10 @@ def _infer_type_new_call(self, caller, context):
443448
return None
444449

445450
# Verify the name
446-
name = next(caller.args[1].infer(context=context))
451+
try:
452+
name = next(caller.args[1].infer(context=context))
453+
except StopIteration as e:
454+
raise InferenceError(context=context) from e
447455
if name.__class__.__name__ != "Const":
448456
# Not a valid name, needs to be a const.
449457
return None
@@ -452,24 +460,39 @@ def _infer_type_new_call(self, caller, context):
452460
return None
453461

454462
# Verify the bases
455-
bases = next(caller.args[2].infer(context=context))
463+
try:
464+
bases = next(caller.args[2].infer(context=context))
465+
except StopIteration as e:
466+
raise InferenceError(context=context) from e
456467
if bases.__class__.__name__ != "Tuple":
457468
# Needs to be a tuple.
458469
return None
459-
inferred_bases = [next(elt.infer(context=context)) for elt in bases.elts]
470+
try:
471+
inferred_bases = [next(elt.infer(context=context)) for elt in bases.elts]
472+
except StopIteration as e:
473+
raise InferenceError(context=context) from e
460474
if any(base.__class__.__name__ != "ClassDef" for base in inferred_bases):
461475
# All the bases needs to be Classes
462476
return None
463477

464478
# Verify the attributes.
465-
attrs = next(caller.args[3].infer(context=context))
479+
try:
480+
attrs = next(caller.args[3].infer(context=context))
481+
except StopIteration as e:
482+
raise InferenceError(context=context) from e
466483
if attrs.__class__.__name__ != "Dict":
467484
# Needs to be a dictionary.
468485
return None
469486
cls_locals = collections.defaultdict(list)
470487
for key, value in attrs.items:
471-
key = next(key.infer(context=context))
472-
value = next(value.infer(context=context))
488+
try:
489+
key = next(key.infer(context=context))
490+
except StopIteration as e:
491+
raise InferenceError(context=context) from e
492+
try:
493+
value = next(value.infer(context=context))
494+
except StopIteration as e:
495+
raise InferenceError(context=context) from e
473496
# Ignore non string keys
474497
if key.__class__.__name__ == "Const" and isinstance(key.value, str):
475498
cls_locals[key.value].append(value)

astroid/brain/brain_builtin_inference.py

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ def is_iterable(n):
329329

330330
try:
331331
inferred = next(arg.infer(context))
332-
except (InferenceError, NameInferenceError) as exc:
332+
except (InferenceError, NameInferenceError, StopIteration) as exc:
333333
raise UseInferenceDefault from exc
334334
if isinstance(inferred, nodes.Dict):
335335
items = inferred.items
@@ -432,11 +432,11 @@ def infer_super(node, context=None):
432432
else:
433433
try:
434434
mro_pointer = next(node.args[0].infer(context=context))
435-
except InferenceError as exc:
435+
except (InferenceError, StopIteration) as exc:
436436
raise UseInferenceDefault from exc
437437
try:
438438
mro_type = next(node.args[1].infer(context=context))
439-
except InferenceError as exc:
439+
except (InferenceError, StopIteration) as exc:
440440
raise UseInferenceDefault from exc
441441

442442
if mro_pointer is util.Uninferable or mro_type is util.Uninferable:
@@ -458,7 +458,7 @@ def _infer_getattr_args(node, context):
458458
try:
459459
obj = next(node.args[0].infer(context=context))
460460
attr = next(node.args[1].infer(context=context))
461-
except InferenceError as exc:
461+
except (InferenceError, StopIteration) as exc:
462462
raise UseInferenceDefault from exc
463463

464464
if obj is util.Uninferable or attr is util.Uninferable:
@@ -496,7 +496,7 @@ def infer_getattr(node, context=None):
496496
# Try to infer the default and return it instead.
497497
try:
498498
return next(node.args[2].infer(context=context))
499-
except InferenceError as exc:
499+
except (StopIteration, InferenceError) as exc:
500500
raise UseInferenceDefault from exc
501501

502502
raise UseInferenceDefault
@@ -544,7 +544,7 @@ def infer_callable(node, context=None):
544544
argument = node.args[0]
545545
try:
546546
inferred = next(argument.infer(context=context))
547-
except InferenceError:
547+
except (InferenceError, StopIteration):
548548
return util.Uninferable
549549
if inferred is util.Uninferable:
550550
return util.Uninferable
@@ -564,7 +564,7 @@ def infer_property(node, context=None):
564564
getter = node.args[0]
565565
try:
566566
inferred = next(getter.infer(context=context))
567-
except InferenceError as exc:
567+
except (InferenceError, StopIteration) as exc:
568568
raise UseInferenceDefault from exc
569569

570570
if not isinstance(inferred, (nodes.FunctionDef, nodes.Lambda)):
@@ -592,7 +592,7 @@ def infer_bool(node, context=None):
592592
argument = node.args[0]
593593
try:
594594
inferred = next(argument.infer(context=context))
595-
except InferenceError:
595+
except (InferenceError, StopIteration):
596596
return util.Uninferable
597597
if inferred is util.Uninferable:
598598
return util.Uninferable
@@ -682,7 +682,7 @@ def infer_issubclass(callnode, context=None):
682682

683683
try:
684684
obj_type = next(obj_node.infer(context=context))
685-
except InferenceError as exc:
685+
except (InferenceError, StopIteration) as exc:
686686
raise UseInferenceDefault from exc
687687
if not isinstance(obj_type, nodes.ClassDef):
688688
raise UseInferenceDefault("TypeError: arg 1 must be class")
@@ -749,13 +749,19 @@ def _class_or_tuple_to_container(node, context=None):
749749
# Move inferences results into container
750750
# to simplify later logic
751751
# raises InferenceError if any of the inferences fall through
752-
node_infer = next(node.infer(context=context))
752+
try:
753+
node_infer = next(node.infer(context=context))
754+
except StopIteration as e:
755+
raise InferenceError(node=node, context=context) from e
753756
# arg2 MUST be a type or a TUPLE of types
754757
# for isinstance
755758
if isinstance(node_infer, nodes.Tuple):
756-
class_container = [
757-
next(node.infer(context=context)) for node in node_infer.elts
758-
]
759+
try:
760+
class_container = [
761+
next(node.infer(context=context)) for node in node_infer.elts
762+
]
763+
except StopIteration as e:
764+
raise InferenceError(node=node, context=context) from e
759765
class_container = [
760766
klass_node for klass_node in class_container if klass_node is not None
761767
]
@@ -865,7 +871,7 @@ def _build_dict_with_elements(elements):
865871
values = call.positional_arguments[0]
866872
try:
867873
inferred_values = next(values.infer(context=context))
868-
except InferenceError:
874+
except (InferenceError, StopIteration):
869875
return _build_dict_with_elements([])
870876
if inferred_values is util.Uninferable:
871877
return _build_dict_with_elements([])

astroid/brain/brain_functools.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def _functools_partial_inference(node, context=None):
7474
partial_function = call.positional_arguments[0]
7575
try:
7676
inferred_wrapped_function = next(partial_function.infer(context=context))
77-
except InferenceError as exc:
77+
except (InferenceError, StopIteration) as exc:
7878
raise UseInferenceDefault from exc
7979
if inferred_wrapped_function is Uninferable:
8080
raise UseInferenceDefault("Cannot infer the wrapped function")

astroid/brain/brain_multiprocessing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def Manager():
3636
try:
3737
context = next(node["default"].infer())
3838
base = next(node["base"].infer())
39-
except InferenceError:
39+
except (InferenceError, StopIteration):
4040
return module
4141

4242
for node in (context, base):

astroid/brain/brain_namedtuple_enum.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ def _infer_first(node, context):
5454
raise UseInferenceDefault
5555
try:
5656
value = next(node.infer(context=context))
57-
if value is util.Uninferable:
58-
raise UseInferenceDefault()
59-
return value
6057
except StopIteration as exc:
6158
raise InferenceError from exc
59+
if value is util.Uninferable:
60+
raise UseInferenceDefault()
61+
return value
6262

6363

6464
def _find_func_form_arguments(node, context):
@@ -184,10 +184,15 @@ def infer_named_tuple(node, context=None):
184184
node, tuple_base_name, context=context
185185
)
186186
call_site = arguments.CallSite.from_call(node, context=context)
187-
func = next(extract_node("import collections; collections.namedtuple").infer())
187+
node = extract_node("import collections; collections.namedtuple")
188+
try:
189+
190+
func = next(node.infer())
191+
except StopIteration as e:
192+
raise InferenceError(node=node) from e
188193
try:
189194
rename = next(call_site.infer_argument(func, "rename", context)).bool_value()
190-
except InferenceError:
195+
except (InferenceError, StopIteration):
191196
rename = False
192197

193198
try:
@@ -471,7 +476,10 @@ def infer_typing_namedtuple_class(class_node, context=None):
471476
"""
472477
).format(typename=class_node.name, fields=",".join(annassigns_fields))
473478
node = extract_node(code)
474-
generated_class_node = next(infer_named_tuple(node, context))
479+
try:
480+
generated_class_node = next(infer_named_tuple(node, context))
481+
except StopIteration as e:
482+
raise InferenceError(node=node, context=context) from e
475483
for method in class_node.mymethods():
476484
generated_class_node.locals[method.name] = [method]
477485

@@ -507,7 +515,7 @@ def infer_typing_namedtuple(node, context=None):
507515
# so we extract the args and infer a named tuple.
508516
try:
509517
func = next(node.func.infer())
510-
except InferenceError as exc:
518+
except (InferenceError, StopIteration) as exc:
511519
raise UseInferenceDefault from exc
512520

513521
if func.qname() != "typing.NamedTuple":

astroid/brain/brain_nose.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class Test(unittest.TestCase):
4242
)
4343
try:
4444
case = next(module["a"].infer())
45-
except InferenceError:
45+
except (InferenceError, StopIteration):
4646
return
4747
for method in case.methods():
4848
if method.name.startswith("assert") and "_" not in method.name:

astroid/brain/brain_six.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ def transform_six_add_metaclass(node): # pylint: disable=inconsistent-return-st
189189

190190
try:
191191
func = next(decorator.func.infer())
192-
except InferenceError:
192+
except (InferenceError, StopIteration):
193193
continue
194194
if func.qname() == SIX_ADD_METACLASS and decorator.args:
195195
metaclass = decorator.args[0]

astroid/brain/brain_typing.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def infer_typing_typevar_or_newtype(node, context_itton=None):
115115
"""Infer a typing.TypeVar(...) or typing.NewType(...) call"""
116116
try:
117117
func = next(node.func.infer(context=context_itton))
118-
except InferenceError as exc:
118+
except (InferenceError, StopIteration) as exc:
119119
raise UseInferenceDefault from exc
120120

121121
if func.qname() not in TYPING_TYPEVARS_QUALIFIED:
@@ -145,7 +145,7 @@ def infer_typing_attr(
145145
"""Infer a typing.X[...] subscript"""
146146
try:
147147
value = next(node.value.infer())
148-
except InferenceError as exc:
148+
except (InferenceError, StopIteration) as exc:
149149
raise UseInferenceDefault from exc
150150

151151
if (
@@ -269,7 +269,11 @@ def infer_typing_alias(
269269
or not isinstance(node.parent.targets[0], AssignName)
270270
):
271271
return None
272-
res = next(node.args[0].infer(context=ctx))
272+
try:
273+
res = next(node.args[0].infer(context=ctx))
274+
except StopIteration as e:
275+
raise InferenceError(node=node.args[0], context=context) from e
276+
273277
assign_name = node.parent.targets[0]
274278

275279
class_def = ClassDef(
@@ -333,7 +337,10 @@ def infer_tuple_alias(
333337
node: Call, ctx: context.InferenceContext = None
334338
) -> typing.Iterator[ClassDef]:
335339
"""Infer call to tuple alias as new subscriptable class typing.Tuple."""
336-
res = next(node.args[0].infer(context=ctx))
340+
try:
341+
res = next(node.args[0].infer(context=ctx))
342+
except StopIteration as e:
343+
raise InferenceError(node=node.args[0], context=context) from e
337344
class_def = ClassDef(
338345
name="Tuple",
339346
parent=node.parent,

0 commit comments

Comments
 (0)