From 99e3af2c5fc152ce5b6336ffb560d3ffa56aa737 Mon Sep 17 00:00:00 2001 From: Zen Lee Date: Sun, 22 Jun 2025 04:49:57 +0800 Subject: [PATCH 1/3] Extract and reuse except handler binding check --- pylint/checkers/variables.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 4baf6aabf8..c17e8ad096 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) @@ -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. @@ -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 From c98016621d8c93331c85b82eba94ebc8867b2909 Mon Sep 17 00:00:00 2001 From: Zen Lee Date: Sun, 22 Jun 2025 04:54:02 +0800 Subject: [PATCH 2/3] Add tests --- tests/functional/u/unused/unused_global_variable2.py | 8 ++++++++ tests/functional/u/unused/unused_variable.py | 11 +++++++++++ tests/functional/u/unused/unused_variable.txt | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) 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 From a9b2599f2fffd9ac7b7d729566d8e35cbd76613c Mon Sep 17 00:00:00 2001 From: Zen Lee Date: Sun, 22 Jun 2025 05:01:51 +0800 Subject: [PATCH 3/3] Add changelog --- doc/whatsnew/fragments/10426.false_positive | 3 +++ 1 file changed, 3 insertions(+) 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