From 0325cd5375dec9f5b548a2e1f7673306ba5c7009 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sat, 30 Apr 2022 22:47:29 -0400 Subject: [PATCH 1/4] Fix false positive for `undefined-loop-variable` for lambda in first of two loops --- ChangeLog | 5 +++++ doc/whatsnew/2.13.rst | 5 +++++ pylint/checkers/variables.py | 4 +++- .../u/undefined/undefined_loop_variable.py | 20 +++++++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index e575805e70..eb6838f518 100644 --- a/ChangeLog +++ b/ChangeLog @@ -242,6 +242,11 @@ What's New in Pylint 2.13.8? ============================ Release date: TBA +* Fix a false positive for ``undefined-loop-variable`` for a variable used in a lambda + inside the first of multiple loops. + + Closes #6419 + * Fix a crash when linting a file that passes an integer ``mode=`` to ``open`` diff --git a/doc/whatsnew/2.13.rst b/doc/whatsnew/2.13.rst index 2935bddb5b..c5a2e4e527 100644 --- a/doc/whatsnew/2.13.rst +++ b/doc/whatsnew/2.13.rst @@ -615,6 +615,11 @@ Other Changes Closes #5930 +* Fix a false positive for ``undefined-loop-variable`` for a variable used in a lambda + inside the first of multiple loops. + + Closes #6419 + * Fix a crash when linting a file that passes an integer ``mode=`` to ``open`` diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 2fa33f3246..48be1c6e73 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -2198,7 +2198,9 @@ def _loopvar_name(self, node: astroid.Name) -> None: # the usage is safe because the function will not be defined either if # the variable is not defined. scope = node.scope() - if isinstance(scope, nodes.FunctionDef) and any( + # FunctionDef subclasses Lambda due to suboptimal ontology. Check both. + # See https://github.com/PyCQA/astroid/issues/291 (fix abandoned in a stale branch) + if isinstance(scope, nodes.Lambda) and any( asmt.scope().parent_of(scope) for asmt in astmts ): return diff --git a/tests/functional/u/undefined/undefined_loop_variable.py b/tests/functional/u/undefined/undefined_loop_variable.py index 956773e310..0270c6b532 100644 --- a/tests/functional/u/undefined/undefined_loop_variable.py +++ b/tests/functional/u/undefined/undefined_loop_variable.py @@ -103,3 +103,23 @@ def handle_line(layne): ] for item in lst ] + + +def lambda_in_first_of_two_loops(): + """https://github.com/PyCQA/pylint/issues/6419""" + my_list = [] + for thing in my_list: + print_it = lambda: print(thing) # pylint: disable=cell-var-from-loop + print_it() + + for thing in my_list: + print(thing) + + +def variable_name_assigned_in_body_of_second_loop(): + for alias in tuple(bigger): + continue + for _ in range(3): + alias = True + if alias: + print(alias) From e2fc6c7058bf3e94c942e11065852d1b19400c24 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sat, 30 Apr 2022 22:57:54 -0400 Subject: [PATCH 2/4] add "suboptimal" to dictionary --- .pyenchant_pylint_custom_dict.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.pyenchant_pylint_custom_dict.txt b/.pyenchant_pylint_custom_dict.txt index 9645d3b3a3..714650f60e 100644 --- a/.pyenchant_pylint_custom_dict.txt +++ b/.pyenchant_pylint_custom_dict.txt @@ -281,6 +281,7 @@ stmt str stringified subclasses +suboptimal subdicts subgraphs sublists From 5ac6687058c0a6c058bc007c771c8a45575ae7d3 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sat, 30 Apr 2022 23:00:29 -0400 Subject: [PATCH 3/4] make this easier to backport --- .pyenchant_pylint_custom_dict.txt | 1 - pylint/checkers/variables.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.pyenchant_pylint_custom_dict.txt b/.pyenchant_pylint_custom_dict.txt index 714650f60e..9645d3b3a3 100644 --- a/.pyenchant_pylint_custom_dict.txt +++ b/.pyenchant_pylint_custom_dict.txt @@ -281,7 +281,6 @@ stmt str stringified subclasses -suboptimal subdicts subgraphs sublists diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 48be1c6e73..09fc1641ad 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -2198,7 +2198,7 @@ def _loopvar_name(self, node: astroid.Name) -> None: # the usage is safe because the function will not be defined either if # the variable is not defined. scope = node.scope() - # FunctionDef subclasses Lambda due to suboptimal ontology. Check both. + # FunctionDef subclasses Lambda due to a curious ontology. Check both. # See https://github.com/PyCQA/astroid/issues/291 (fix abandoned in a stale branch) if isinstance(scope, nodes.Lambda) and any( asmt.scope().parent_of(scope) for asmt in astmts From f40bf86fa1f015ed6109b5ad3de935076e38c6e5 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sun, 1 May 2022 11:30:46 -0400 Subject: [PATCH 4/4] Add TODO Co-authored-by: Pierre Sassoulas --- pylint/checkers/variables.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 09fc1641ad..a309b329d0 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -2199,7 +2199,8 @@ def _loopvar_name(self, node: astroid.Name) -> None: # the variable is not defined. scope = node.scope() # FunctionDef subclasses Lambda due to a curious ontology. Check both. - # See https://github.com/PyCQA/astroid/issues/291 (fix abandoned in a stale branch) + # See https://github.com/PyCQA/astroid/issues/291 + # TODO: Revisit when astroid 3.0 includes the change if isinstance(scope, nodes.Lambda) and any( asmt.scope().parent_of(scope) for asmt in astmts ):