summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Walls <jacobtylerwalls@gmail.com>2021-12-13 12:02:46 -0500
committerGitHub <noreply@github.com>2021-12-13 18:02:46 +0100
commit35254c29eb3a0f1c7847cfcb3451501a4180373d (patch)
tree56d5a408a98cb159e19cfb91718ffb0ac3e9d493
parente3e5aebae7a96eb02b0f32e14f07c873f8d2519f (diff)
downloadpylint-git-35254c29eb3a0f1c7847cfcb3451501a4180373d.tar.gz
Fix false-positive 'used-before-assignment' for assignments in except blocks following try blocks that return (#5506)
-rw-r--r--ChangeLog12
-rw-r--r--doc/whatsnew/2.13.rst12
-rw-r--r--pylint/checkers/variables.py22
-rw-r--r--tests/functional/u/use/used_before_assignment_except_handler_for_try_with_return.py15
-rw-r--r--tests/functional/u/use/used_before_assignment_except_handler_for_try_with_return.txt1
5 files changed, 55 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index a90ade1cc..ae0c1d6e2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,15 +11,21 @@ Release date: TBA
..
Put new features here and also in 'doc/whatsnew/2.13.rst'
+* ``used-before-assignment`` now considers that assignments in a try block
+ may not have occurred when the except or finally blocks are executed.
+
+ Closes #85, #2615
+
* ``used-before-assignment`` now assumes that assignments in except blocks
may not have occurred and warns accordingly.
Closes #4761
-* ``used-before-assignment`` now considers that assignments in a try block
- may not have occurred when the except or finally blocks are executed.
+* When evaluating statements after an except block, ``used-before-assignment``
+ assumes that assignments in the except blocks took place if the
+ corresponding try block contained a return statement.
- Closes #85, #2615
+ Closes #5500
* ``used-before-assignment`` now checks names in try blocks.
diff --git a/doc/whatsnew/2.13.rst b/doc/whatsnew/2.13.rst
index b3372278d..8555108c1 100644
--- a/doc/whatsnew/2.13.rst
+++ b/doc/whatsnew/2.13.rst
@@ -43,15 +43,21 @@ Other Changes
Closes #5323
+* ``used-before-assignment`` now considers that assignments in a try block
+ may not have occurred when the except or finally blocks are executed.
+
+ Closes #85, #2615
+
* ``used-before-assignment`` now assumes that assignments in except blocks
may not have occurred and warns accordingly.
Closes #4761
-* ``used-before-assignment`` now considers that assignments in a try block
- may not have occurred when the except or finally blocks are executed.
+* When evaluating statements after an except block, ``used-before-assignment``
+ assumes that assignments in the except blocks took place if the
+ corresponding try block contained a return statement.
- Closes #85, #2615
+ Closes #5500
* ``used-before-assignment`` now checks names in try blocks.
diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py
index 0a4a21c18..86b7eb669 100644
--- a/pylint/checkers/variables.py
+++ b/pylint/checkers/variables.py
@@ -408,7 +408,8 @@ MSGS = {
"Emitted when a local variable is accessed before its assignment took place. "
"Assignments in try blocks are assumed not to have occurred when evaluating "
"associated except/finally blocks. Assignments in except blocks are assumed "
- "not to have occurred when evaluating statements outside the block.",
+ "not to have occurred when evaluating statements outside the block, except "
+ "when the associated try block contains a return statement.",
),
"E0602": (
"Undefined variable %r",
@@ -656,6 +657,25 @@ scope_type : {self._atomic.scope_type}
and isinstance(
n.statement(future=True).parent.parent, nodes.TryExcept
)
+ # If the try block returns we assume that assignments in the except
+ # handlers could have happened.
+ and (
+ not any(
+ isinstance(try_statement, nodes.Return)
+ for try_statement in n.statement(
+ future=True
+ ).parent.parent.body
+ )
+ # But not if this node is in the final block, which will
+ # execute before the return.
+ or (
+ isinstance(node_statement.parent, nodes.TryFinally)
+ and node_statement in node_statement.parent.finalbody
+ and n.statement(future=True).parent.parent.parent.parent_of(
+ node_statement
+ )
+ )
+ )
)
or n.statement(future=True).parent.parent_of(node)
]
diff --git a/tests/functional/u/use/used_before_assignment_except_handler_for_try_with_return.py b/tests/functional/u/use/used_before_assignment_except_handler_for_try_with_return.py
new file mode 100644
index 000000000..d976a46b2
--- /dev/null
+++ b/tests/functional/u/use/used_before_assignment_except_handler_for_try_with_return.py
@@ -0,0 +1,15 @@
+"""Tests for used-before-assignment with assignments in except handlers after
+try blocks with return statements.
+See: https://github.com/PyCQA/pylint/issues/5500.
+"""
+def function():
+ """Assume except blocks execute if the try block returns."""
+ try:
+ success_message = "success message"
+ return success_message
+ except ValueError:
+ failure_message = "failure message"
+ finally:
+ print(failure_message) # [used-before-assignment]
+
+ return failure_message
diff --git a/tests/functional/u/use/used_before_assignment_except_handler_for_try_with_return.txt b/tests/functional/u/use/used_before_assignment_except_handler_for_try_with_return.txt
new file mode 100644
index 000000000..e5d8d3de8
--- /dev/null
+++ b/tests/functional/u/use/used_before_assignment_except_handler_for_try_with_return.txt
@@ -0,0 +1 @@
+used-before-assignment:13:14:13:29:function:Using variable 'failure_message' before assignment:UNDEFINED