summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorsten Marek <shlomme@gmail.com>2014-07-25 10:42:41 +0200
committerTorsten Marek <shlomme@gmail.com>2014-07-25 10:42:41 +0200
commitb626280fe7b2eca2359441b85535846b41bad73f (patch)
tree5903baa59e4ba059e2770b8b23545799e4e47ac0
parent51c5dc1b89d899fa750440f11df6b561560826e4 (diff)
downloadpylint-git-b626280fe7b2eca2359441b85535846b41bad73f.tar.gz
Fix more edge cases in the cell-var-from-loop warning (Closes: #233).
-rw-r--r--checkers/variables.py10
-rw-r--r--test/input/func_loopvar_in_closure.py18
-rw-r--r--test/messages/func_loopvar_in_closure.txt12
3 files changed, 33 insertions, 7 deletions
diff --git a/checkers/variables.py b/checkers/variables.py
index 8f8ee87a0..3b9bcda2c 100644
--- a/checkers/variables.py
+++ b/checkers/variables.py
@@ -542,9 +542,15 @@ builtins. Remember that you should avoid to define new builtins when possible.'
self.add_message('global-statement', node=node)
def _check_late_binding_closure(self, node, assignment_node, scope_type):
+ def _is_direct_lambda_call():
+ return (isinstance(node_scope.parent, astroid.CallFunc)
+ and node_scope.parent.func is node_scope)
+
node_scope = node.scope()
if not isinstance(node_scope, (astroid.Lambda, astroid.Function)):
return
+ if isinstance(node.parent, astroid.Arguments):
+ return
if isinstance(assignment_node, astroid.Comprehension):
if assignment_node.parent.parent_of(node.scope()):
@@ -557,7 +563,9 @@ builtins. Remember that you should avoid to define new builtins when possible.'
break
maybe_for = maybe_for.parent
else:
- if maybe_for.parent_of(node_scope) and not isinstance(node_scope.statement(), astroid.Return):
+ if (maybe_for.parent_of(node_scope)
+ and not _is_direct_lambda_call()
+ and not isinstance(node_scope.statement(), astroid.Return)):
self.add_message('cell-var-from-loop', node=node, args=node.name)
def _loopvar_name(self, node, name):
diff --git a/test/input/func_loopvar_in_closure.py b/test/input/func_loopvar_in_closure.py
index 32b7a6c6e..3a791d335 100644
--- a/test/input/func_loopvar_in_closure.py
+++ b/test/input/func_loopvar_in_closure.py
@@ -53,6 +53,23 @@ def good_case7():
return lambda: -1
+def good_case8():
+ """Lambda defined and called in loop."""
+ for i in range(10):
+ print (lambda x: i + x)(1)
+
+
+def good_case9():
+ """Another eager binding of the cell variable."""
+ funs = []
+ for i in range(10):
+ def func(bound_i=i):
+ """Ignore."""
+ return bound_i
+ funs.append(func)
+ return funs
+
+
def bad_case():
"""Closing over a loop variable."""
lst = []
@@ -112,3 +129,4 @@ def bad_case6():
print j
lst.append(lambda: i)
return lst
+
diff --git a/test/messages/func_loopvar_in_closure.txt b/test/messages/func_loopvar_in_closure.txt
index 6ca613a59..5b068f45d 100644
--- a/test/messages/func_loopvar_in_closure.txt
+++ b/test/messages/func_loopvar_in_closure.txt
@@ -1,8 +1,8 @@
W: 21:good_case3: Unused variable 'i'
W: 45:good_case6.<lambda>: Using possibly undefined loop variable 'i'
-W: 61:bad_case.<lambda>: Cell variable i defined in loop
-W: 66:bad_case2.<lambda>: Cell variable i defined in loop
-W: 74:bad_case3.<lambda>: Cell variable j defined in loop
-W: 84:bad_case4.nested: Cell variable i defined in loop
-W:105:bad_case5.<lambda>: Cell variable i defined in loop
-W:113:bad_case6.<lambda>: Cell variable i defined in loop
+W: 78:bad_case.<lambda>: Cell variable i defined in loop
+W: 83:bad_case2.<lambda>: Cell variable i defined in loop
+W: 91:bad_case3.<lambda>: Cell variable j defined in loop
+W:101:bad_case4.nested: Cell variable i defined in loop
+W:122:bad_case5.<lambda>: Cell variable i defined in loop
+W:130:bad_case6.<lambda>: Cell variable i defined in loop