summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Frost <indigo@bitglue.com>2015-02-14 20:42:06 -0500
committerPhil Frost <indigo@bitglue.com>2015-02-14 20:42:06 -0500
commit0b1ce4c316d53c9842f2df4ab08856f4f6dc0d83 (patch)
tree3ac5095aa090a814a729d09f299b5806217c6698
parent8f539dfc70e88af5c287c898799f9bd1aae6512d (diff)
parent84b7dd63a379b30968f028a0346ec1958c82fbbe (diff)
downloadpyflakes-0b1ce4c316d53c9842f2df4ab08856f4f6dc0d83.tar.gz
Merge pull request #12 from chevah/885140-del-if-while
[#885140] Update del handling in if and while statements.
-rw-r--r--pyflakes/checker.py18
-rw-r--r--pyflakes/test/test_undefined_names.py68
2 files changed, 86 insertions, 0 deletions
diff --git a/pyflakes/checker.py b/pyflakes/checker.py
index 2c192af..0ff1bb1 100644
--- a/pyflakes/checker.py
+++ b/pyflakes/checker.py
@@ -531,9 +531,27 @@ class Checker(object):
self.addBinding(node, binding)
def handleNodeDelete(self, node):
+
+ def on_conditional_branch():
+ """
+ Return `True` if node is part of a conditional body.
+ """
+ current = getattr(node, 'parent', None)
+ while current:
+ if isinstance(current, (ast.If, ast.While, ast.IfExp)):
+ return True
+ current = getattr(current, 'parent', None)
+ return False
+
name = getNodeName(node)
if not name:
return
+
+ if on_conditional_branch():
+ # We can not predict if this conditional branch is going to
+ # be executed.
+ return
+
if isinstance(self.scope, FunctionScope) and name in self.scope.globals:
self.scope.globals.remove(name)
else:
diff --git a/pyflakes/test/test_undefined_names.py b/pyflakes/test/test_undefined_names.py
index 4b230cc..bbded24 100644
--- a/pyflakes/test/test_undefined_names.py
+++ b/pyflakes/test/test_undefined_names.py
@@ -122,6 +122,74 @@ class Test(TestCase):
"""Del an undefined name."""
self.flakes('del a', m.UndefinedName)
+ def test_delConditional(self):
+ """
+ Ignores conditional bindings deletion.
+ """
+ self.flakes('''
+ context = None
+ test = True
+ if False:
+ del(test)
+ assert(test)
+ ''')
+
+ def test_delConditionalNested(self):
+ """
+ Ignored conditional bindings deletion even if they are nested in other
+ blocks.
+ """
+ self.flakes('''
+ context = None
+ test = True
+ if False:
+ with context():
+ del(test)
+ assert(test)
+ ''')
+
+ def test_delWhile(self):
+ """
+ Ignore bindings deletion if called inside the body of a while
+ statement.
+ """
+ self.flakes('''
+ def test():
+ foo = 'bar'
+ while False:
+ del foo
+ assert(foo)
+ ''')
+
+ def test_delWhileTestUsage(self):
+ """
+ Ignore bindings deletion if called inside the body of a while
+ statement and name is used inside while's test part.
+ """
+ self.flakes('''
+ def _worker():
+ o = True
+ while o is not True:
+ del o
+ o = False
+ ''')
+
+ def test_delWhileNested(self):
+ """
+ Ignore bindings deletions if node is part of while's test, even when
+ del is in a nested block.
+ """
+ self.flakes('''
+ context = None
+ def _worker():
+ o = True
+ while o is not True:
+ while True:
+ with context():
+ del o
+ o = False
+ ''')
+
def test_globalFromNestedScope(self):
"""Global names are available from nested scopes."""
self.flakes('''