summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Liu <david@cs.toronto.edu>2021-09-20 16:11:44 -0400
committerGitHub <noreply@github.com>2021-09-20 22:11:44 +0200
commitfb750d39f82dd58342a7683ac5e03b38ba64ae4a (patch)
treeca09ea459879419a29c17e5b2a9f84b675a66b8d
parent24cbf8c33120db595c3dd9443418e1b8472839fd (diff)
downloadpylint-git-fb750d39f82dd58342a7683ac5e03b38ba64ae4a.tar.gz
Fix bug with cell-var-from-loop and kw_defaults (#5045)
* Fix bug with cell-var-from-loop and kw_defaults * Use more efficient generator for defaults and add issue link * Fix test output for cellvar_escaping_loop Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
-rw-r--r--ChangeLog5
-rw-r--r--pylint/checkers/utils.py13
-rw-r--r--tests/functional/c/cellvar_escaping_loop.py16
-rw-r--r--tests/functional/c/cellvar_escaping_loop.txt26
4 files changed, 43 insertions, 17 deletions
diff --git a/ChangeLog b/ChangeLog
index bb023b552..c078c2ae2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -29,6 +29,11 @@ Release date: TBA
Closes #5029
+* Fixed false positive for ``cell-var-from-loop`` when variable is used as the default
+ value for a keyword-only parameter.
+
+ Closes #5012
+
What's New in Pylint 2.11.1?
============================
diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py
index 305a4fc94..87c12433d 100644
--- a/pylint/checkers/utils.py
+++ b/pylint/checkers/utils.py
@@ -402,10 +402,15 @@ def is_default_argument(
if not scope:
scope = node.scope()
if isinstance(scope, (nodes.FunctionDef, nodes.Lambda)):
- for default_node in scope.args.defaults:
- for default_name_node in default_node.nodes_of_class(nodes.Name):
- if default_name_node is node:
- return True
+ all_defaults = itertools.chain(
+ scope.args.defaults, (d for d in scope.args.kw_defaults if d is not None)
+ )
+ return any(
+ default_name_node is node
+ for default_node in all_defaults
+ for default_name_node in default_node.nodes_of_class(nodes.Name)
+ )
+
return False
diff --git a/tests/functional/c/cellvar_escaping_loop.py b/tests/functional/c/cellvar_escaping_loop.py
index 5520fe949..502ec75f1 100644
--- a/tests/functional/c/cellvar_escaping_loop.py
+++ b/tests/functional/c/cellvar_escaping_loop.py
@@ -93,6 +93,22 @@ def good_case_issue3107():
next(filter(lambda j, ix=i[0]: j == ix, [1, 3]))
+def good_case_issue_5012():
+ """Eager binding of cell variable when used as the default value of a keyword-only argument.
+ https://github.com/PyCQA/pylint/issues/5012
+ """
+ funs = []
+ for i in range(5):
+ def func(*, _i=i):
+ print(_i)
+ funs.append(func)
+
+ def func2(_i=i):
+ print(_i)
+ funs.append(func2)
+
+ return funs
+
def bad_case():
"""Closing over a loop variable."""
lst = []
diff --git a/tests/functional/c/cellvar_escaping_loop.txt b/tests/functional/c/cellvar_escaping_loop.txt
index 4513d833f..dda2d46d2 100644
--- a/tests/functional/c/cellvar_escaping_loop.txt
+++ b/tests/functional/c/cellvar_escaping_loop.txt
@@ -1,13 +1,13 @@
-cell-var-from-loop:101:27:bad_case.<lambda>:Cell variable i defined in loop:HIGH
-cell-var-from-loop:106:20:bad_case2.<lambda>:Cell variable i defined in loop:HIGH
-cell-var-from-loop:114:27:bad_case3.<lambda>:Cell variable j defined in loop:HIGH
-cell-var-from-loop:124:19:bad_case4.nested:Cell variable i defined in loop:HIGH
-cell-var-from-loop:145:20:bad_case5.<lambda>:Cell variable i defined in loop:HIGH
-cell-var-from-loop:153:27:bad_case6.<lambda>:Cell variable i defined in loop:HIGH
-cell-var-from-loop:161:12:bad_case7.<lambda>:Cell variable x defined in loop:HIGH
-cell-var-from-loop:162:14:bad_case7.<lambda>:Cell variable y defined in loop:HIGH
-cell-var-from-loop:171:27:bad_case8.<lambda>:Cell variable j defined in loop:HIGH
-cell-var-from-loop:181:27:bad_case9.<lambda>:Cell variable i defined in loop:HIGH
-cell-var-from-loop:190:26:bad_case10.func.func2:Cell variable i defined in loop:HIGH
-cell-var-from-loop:202:17:bad_case_issue2846.<lambda>:Cell variable n defined in loop:HIGH
-cell-var-from-loop:207:18:bad_case_issue2846.<lambda>:Cell variable n defined in loop:HIGH
+cell-var-from-loop:117:27:bad_case.<lambda>:Cell variable i defined in loop:HIGH
+cell-var-from-loop:122:20:bad_case2.<lambda>:Cell variable i defined in loop:HIGH
+cell-var-from-loop:130:27:bad_case3.<lambda>:Cell variable j defined in loop:HIGH
+cell-var-from-loop:140:19:bad_case4.nested:Cell variable i defined in loop:HIGH
+cell-var-from-loop:161:20:bad_case5.<lambda>:Cell variable i defined in loop:HIGH
+cell-var-from-loop:169:27:bad_case6.<lambda>:Cell variable i defined in loop:HIGH
+cell-var-from-loop:177:12:bad_case7.<lambda>:Cell variable x defined in loop:HIGH
+cell-var-from-loop:178:14:bad_case7.<lambda>:Cell variable y defined in loop:HIGH
+cell-var-from-loop:187:27:bad_case8.<lambda>:Cell variable j defined in loop:HIGH
+cell-var-from-loop:197:27:bad_case9.<lambda>:Cell variable i defined in loop:HIGH
+cell-var-from-loop:206:26:bad_case10.func.func2:Cell variable i defined in loop:HIGH
+cell-var-from-loop:218:17:bad_case_issue2846.<lambda>:Cell variable n defined in loop:HIGH
+cell-var-from-loop:223:18:bad_case_issue2846.<lambda>:Cell variable n defined in loop:HIGH