Skip to content

Commit 35254c2

Browse files
Fix false-positive 'used-before-assignment' for assignments in except blocks following try blocks that return (#5506)
1 parent e3e5aeb commit 35254c2

File tree

5 files changed

+55
-7
lines changed

5 files changed

+55
-7
lines changed

ChangeLog

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,21 @@ Release date: TBA
1111
..
1212
Put new features here and also in 'doc/whatsnew/2.13.rst'
1313

14+
* ``used-before-assignment`` now considers that assignments in a try block
15+
may not have occurred when the except or finally blocks are executed.
16+
17+
Closes #85, #2615
18+
1419
* ``used-before-assignment`` now assumes that assignments in except blocks
1520
may not have occurred and warns accordingly.
1621

1722
Closes #4761
1823

19-
* ``used-before-assignment`` now considers that assignments in a try block
20-
may not have occurred when the except or finally blocks are executed.
24+
* When evaluating statements after an except block, ``used-before-assignment``
25+
assumes that assignments in the except blocks took place if the
26+
corresponding try block contained a return statement.
2127

22-
Closes #85, #2615
28+
Closes #5500
2329

2430
* ``used-before-assignment`` now checks names in try blocks.
2531

doc/whatsnew/2.13.rst

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,21 @@ Other Changes
4343

4444
Closes #5323
4545

46+
* ``used-before-assignment`` now considers that assignments in a try block
47+
may not have occurred when the except or finally blocks are executed.
48+
49+
Closes #85, #2615
50+
4651
* ``used-before-assignment`` now assumes that assignments in except blocks
4752
may not have occurred and warns accordingly.
4853

4954
Closes #4761
5055

51-
* ``used-before-assignment`` now considers that assignments in a try block
52-
may not have occurred when the except or finally blocks are executed.
56+
* When evaluating statements after an except block, ``used-before-assignment``
57+
assumes that assignments in the except blocks took place if the
58+
corresponding try block contained a return statement.
5359

54-
Closes #85, #2615
60+
Closes #5500
5561

5662
* ``used-before-assignment`` now checks names in try blocks.
5763

pylint/checkers/variables.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,8 @@ def _has_locals_call_after_node(stmt, scope):
408408
"Emitted when a local variable is accessed before its assignment took place. "
409409
"Assignments in try blocks are assumed not to have occurred when evaluating "
410410
"associated except/finally blocks. Assignments in except blocks are assumed "
411-
"not to have occurred when evaluating statements outside the block.",
411+
"not to have occurred when evaluating statements outside the block, except "
412+
"when the associated try block contains a return statement.",
412413
),
413414
"E0602": (
414415
"Undefined variable %r",
@@ -656,6 +657,25 @@ def get_next_to_consume(self, node):
656657
and isinstance(
657658
n.statement(future=True).parent.parent, nodes.TryExcept
658659
)
660+
# If the try block returns we assume that assignments in the except
661+
# handlers could have happened.
662+
and (
663+
not any(
664+
isinstance(try_statement, nodes.Return)
665+
for try_statement in n.statement(
666+
future=True
667+
).parent.parent.body
668+
)
669+
# But not if this node is in the final block, which will
670+
# execute before the return.
671+
or (
672+
isinstance(node_statement.parent, nodes.TryFinally)
673+
and node_statement in node_statement.parent.finalbody
674+
and n.statement(future=True).parent.parent.parent.parent_of(
675+
node_statement
676+
)
677+
)
678+
)
659679
)
660680
or n.statement(future=True).parent.parent_of(node)
661681
]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""Tests for used-before-assignment with assignments in except handlers after
2+
try blocks with return statements.
3+
See: https://github.com/PyCQA/pylint/issues/5500.
4+
"""
5+
def function():
6+
"""Assume except blocks execute if the try block returns."""
7+
try:
8+
success_message = "success message"
9+
return success_message
10+
except ValueError:
11+
failure_message = "failure message"
12+
finally:
13+
print(failure_message) # [used-before-assignment]
14+
15+
return failure_message
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
used-before-assignment:13:14:13:29:function:Using variable 'failure_message' before assignment:UNDEFINED

0 commit comments

Comments
 (0)