Skip to content

Fix unused-variable false positive when using same name for multiple exceptions #10436

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/whatsnew/fragments/10426.false_positive
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix a false positive for ``unused-variable`` when multiple except handlers bind the same name under a try block.

Closes #10426
15 changes: 12 additions & 3 deletions pylint/checkers/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -2836,9 +2836,7 @@ def _check_is_unused(
return

# Special case for exception variable
if isinstance(stmt.parent, nodes.ExceptHandler) and any(
n.name == name for n in stmt.parent.nodes_of_class(nodes.Name)
):
if self._is_exception_binding_used_in_handler(stmt, name):
return

self.add_message(message_name, args=name, node=stmt)
Expand Down Expand Up @@ -2914,6 +2912,15 @@ def _check_unused_arguments(

self.add_message("unused-argument", args=name, node=stmt, confidence=confidence)

def _is_exception_binding_used_in_handler(
self, stmt: nodes.NodeNG, name: str
) -> bool:
return (
isinstance(stmt.parent, nodes.ExceptHandler)
and stmt is stmt.parent.name
and any(n.name == name for n in stmt.parent.nodes_of_class(nodes.Name))
)

def _check_late_binding_closure(self, node: nodes.Name) -> None:
"""Check whether node is a cell var that is assigned within a containing loop.

Expand Down Expand Up @@ -3245,6 +3252,8 @@ def _check_globals(self, not_consumed: Consumption) -> None:
for node in node_lst:
if in_type_checking_block(node):
continue
if self._is_exception_binding_used_in_handler(node, name):
continue
self.add_message("unused-variable", args=(name,), node=node)

# pylint: disable = too-many-branches
Expand Down
8 changes: 8 additions & 0 deletions tests/functional/u/unused/unused_global_variable2.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,11 @@


VAR = 'pylint' # [unused-variable]


try:
pass
except TypeError as exc:
print(exc)
except ValueError as exc:
print(exc)
11 changes: 11 additions & 0 deletions tests/functional/u/unused/unused_variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,17 @@ def sibling_except_handlers():
except ValueError as e:
print(e)


def test_multiple_except_handlers_under_try():
try:
pass
except TypeError as exc:
print(exc)
except ValueError as exc:
print(exc)
except ArithmeticError as exc:
print(exc)

def func6():
a = 1

Expand Down
2 changes: 1 addition & 1 deletion tests/functional/u/unused/unused_variable.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ unused-variable:150:4:154:26:func4:Unused variable 'error':UNDEFINED
redefined-outer-name:153:8:154:26:func4:Redefining name 'error' from outer scope (line 150):UNDEFINED
unused-variable:161:4:162:12:main:Unused variable 'e':UNDEFINED
undefined-loop-variable:168:10:168:11:main:Using possibly undefined loop variable 'e':UNDEFINED
unused-variable:217:8:218:16:test_regression_8595:Unused variable 'e':UNDEFINED
unused-variable:228:8:229:16:test_regression_8595:Unused variable 'e':UNDEFINED