Skip to content

Commit 135477a

Browse files
Fix a false positive for undefined-loop-variable when a loop else raises or returns (#6480)
Co-authored-by: Pierre Sassoulas <[email protected]>
1 parent 33a9aba commit 135477a

File tree

4 files changed

+33
-1
lines changed

4 files changed

+33
-1
lines changed

ChangeLog

+5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ Release date: TBA
3434

3535
Closes #5930
3636

37+
* Fix a false positive for ``undefined-loop-variable`` when the ``else`` of a ``for``
38+
loop raises or returns.
39+
40+
Closes #5971
41+
3742
* Fix false positive for ``unused-variable`` for classes inside functions
3843
and where a metaclass is provided via a call.
3944

doc/whatsnew/2.13.rst

+5
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,11 @@ Other Changes
607607

608608
Closes #5769
609609

610+
* Fix a false positive for ``undefined-loop-variable`` when the ``else`` of a ``for``
611+
loop raises or returns.
612+
613+
Closes #5971
614+
610615
* Fix false positive for ``unused-variable`` for classes inside functions
611616
and where a metaclass is provided via a call.
612617

pylint/checkers/variables.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -2207,6 +2207,7 @@ def _loopvar_name(self, node: astroid.Name) -> None:
22072207
scope = node.scope()
22082208
# FunctionDef subclasses Lambda due to a curious ontology. Check both.
22092209
# See https://github.com/PyCQA/astroid/issues/291
2210+
# pylint: disable-next=fixme
22102211
# TODO: Revisit when astroid 3.0 includes the change
22112212
if isinstance(scope, nodes.Lambda) and any(
22122213
asmt.scope().parent_of(scope) for asmt in astmts
@@ -2252,11 +2253,16 @@ def _loopvar_name(self, node: astroid.Name) -> None:
22522253
):
22532254
return
22542255

2255-
# For functions we can do more by inferring the length of the itered object
22562256
if not isinstance(assign, nodes.For):
22572257
self.add_message("undefined-loop-variable", args=node.name, node=node)
22582258
return
2259+
if any(
2260+
isinstance(else_stmt, (nodes.Return, nodes.Raise))
2261+
for else_stmt in assign.orelse
2262+
):
2263+
return
22592264

2265+
# For functions we can do more by inferring the length of the itered object
22602266
try:
22612267
inferred = next(assign.iter.infer())
22622268
except astroid.InferenceError:

tests/functional/u/undefined/undefined_loop_variable.py

+16
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,22 @@ def handle_line(layne):
9191
handle_line(layne)
9292

9393

94+
def for_else_returns(iterable):
95+
for thing in iterable:
96+
break
97+
else:
98+
return
99+
print(thing)
100+
101+
102+
def for_else_raises(iterable):
103+
for thing in iterable:
104+
break
105+
else:
106+
raise Exception
107+
print(thing)
108+
109+
94110
lst = []
95111
lst2 = [1, 2, 3]
96112

0 commit comments

Comments
 (0)