From e9b6942ad2ca98583f4cf042e857f0c328882b4c Mon Sep 17 00:00:00 2001 From: Zen Lee <53538590+zenlyj@users.noreply.github.com> Date: Wed, 6 Aug 2025 22:30:54 +0800 Subject: [PATCH] Fix `unused-variable` false positive when using same name for multiple exceptions (#10436) (cherry picked from commit 9e72867c1ac46cb0a2f88abf6f596530c2fa1708) --- doc/whatsnew/fragments/10426.false_positive | 3 +++ pylint/checkers/variables.py | 15 ++++++++++++--- .../u/unused/unused_global_variable2.py | 8 ++++++++ tests/functional/u/unused/unused_variable.py | 11 +++++++++++ tests/functional/u/unused/unused_variable.txt | 2 +- 5 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 doc/whatsnew/fragments/10426.false_positive diff --git a/doc/whatsnew/fragments/10426.false_positive b/doc/whatsnew/fragments/10426.false_positive new file mode 100644 index 0000000000..caa29449ee --- /dev/null +++ b/doc/whatsnew/fragments/10426.false_positive @@ -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 diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 3705ac5c7c..5f5259e79a 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -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) @@ -2913,6 +2911,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. @@ -3238,6 +3245,8 @@ def _check_globals(self, not_consumed: dict[str, nodes.NodeNG]) -> 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 diff --git a/tests/functional/u/unused/unused_global_variable2.py b/tests/functional/u/unused/unused_global_variable2.py index 0722bc63c8..06242bb6e3 100644 --- a/tests/functional/u/unused/unused_global_variable2.py +++ b/tests/functional/u/unused/unused_global_variable2.py @@ -9,3 +9,11 @@ VAR = 'pylint' # [unused-variable] + + +try: + pass +except TypeError as exc: + print(exc) +except ValueError as exc: + print(exc) diff --git a/tests/functional/u/unused/unused_variable.py b/tests/functional/u/unused/unused_variable.py index f15ae75576..b4f5263d56 100644 --- a/tests/functional/u/unused/unused_variable.py +++ b/tests/functional/u/unused/unused_variable.py @@ -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 diff --git a/tests/functional/u/unused/unused_variable.txt b/tests/functional/u/unused/unused_variable.txt index 609ce9fef6..8800488bfb 100644 --- a/tests/functional/u/unused/unused_variable.txt +++ b/tests/functional/u/unused/unused_variable.txt @@ -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