From 175dadf1948969cf78cae6e5e13a6823d74c8c4c Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Fri, 25 Mar 2022 07:37:16 -0400 Subject: Fix false positive for `unused-argument` where nested function uses parent argument as a `nonlocal` (#5906) Co-authored-by: Pierre Sassoulas --- pylint/checkers/variables.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'pylint') diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 08acaefb8..15fa5008b 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -16,6 +16,8 @@ from typing import ( Any, DefaultDict, Dict, + Iterable, + Iterator, List, NamedTuple, Optional, @@ -343,7 +345,9 @@ def _import_name_is_global(stmt, global_names): return False -def _flattened_scope_names(iterator): +def _flattened_scope_names( + iterator: Iterator[Union[nodes.Global, nodes.Nonlocal]] +) -> Set[str]: values = (set(stmt.names) for stmt in iterator) return set(itertools.chain.from_iterable(values)) @@ -2271,7 +2275,9 @@ class VariablesChecker(BaseChecker): if not elements: self.add_message("undefined-loop-variable", args=node.name, node=node) - def _check_is_unused(self, name, node, stmt, global_names, nonlocal_names): + def _check_is_unused( + self, name, node, stmt, global_names, nonlocal_names: Iterable[str] + ): # Ignore some special names specified by user configuration. if self._is_name_ignored(stmt, name): return @@ -2293,7 +2299,7 @@ class VariablesChecker(BaseChecker): argnames = node.argnames() # Care about functions with unknown argument (builtins) if name in argnames: - self._check_unused_arguments(name, node, stmt, argnames) + self._check_unused_arguments(name, node, stmt, argnames, nonlocal_names) else: if stmt.parent and isinstance( stmt.parent, (nodes.Assign, nodes.AnnAssign, nodes.Tuple) @@ -2360,7 +2366,9 @@ class VariablesChecker(BaseChecker): regex = authorized_rgx return regex and regex.match(name) - def _check_unused_arguments(self, name, node, stmt, argnames): + def _check_unused_arguments( + self, name, node, stmt, argnames, nonlocal_names: Iterable[str] + ): is_method = node.is_method() klass = node.parent.frame(future=True) if is_method and isinstance(klass, nodes.ClassDef): @@ -2401,6 +2409,9 @@ class VariablesChecker(BaseChecker): if utils.is_protocol_class(klass): return + if name in nonlocal_names: + return + self.add_message("unused-argument", args=name, node=stmt, confidence=confidence) def _check_late_binding_closure(self, node: nodes.Name) -> None: -- cgit v1.2.1