summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdi Roiban <adi.roiban@chevah.com>2015-02-14 11:00:57 +0000
committerAdi Roiban <adi.roiban@chevah.com>2015-02-14 11:06:33 +0000
commit4bfe6751b4b9b40013cab29769b9c4712558669e (patch)
tree6fc23c2d43d4e6c7c2c11bea6246bcdc2c3c1798
parent8dd58c955cda639ae9155fd42b3c69eca47f5a6c (diff)
downloadpyflakes-4bfe6751b4b9b40013cab29769b9c4712558669e.tar.gz
Update del handling in if and while statements.
-rw-r--r--pyflakes/checker.py38
-rw-r--r--pyflakes/test/test_undefined_names.py67
2 files changed, 105 insertions, 0 deletions
diff --git a/pyflakes/checker.py b/pyflakes/checker.py
index 6d99310..9cbe790 100644
--- a/pyflakes/checker.py
+++ b/pyflakes/checker.py
@@ -531,9 +531,47 @@ class Checker(object):
self.addBinding(node, binding)
def handleNodeDelete(self, node):
+
+ def on_conditional_branch():
+ """
+ Return `True` if node is part of a conditional branch.
+ """
+ current = getattr(node, 'parent', None)
+ while current:
+ if isinstance(current, ast.If):
+ return True
+ current = getattr(current, 'parent', None)
+ return False
+
+ def is_part_of_while_conditional():
+ """
+ Return `True` if node is part of left or right side of a while
+ test.
+ """
+ current = getattr(node, 'parent', None)
+ while current:
+ if isinstance(current, ast.While):
+ for descendant in ast.walk(current.test):
+ if not isinstance(descendant, ast.Name):
+ continue
+ if not node.id == descendant.id:
+ continue
+ 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 is_part_of_while_conditional():
+ 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..4dc0a77 100644
--- a/pyflakes/test/test_undefined_names.py
+++ b/pyflakes/test/test_undefined_names.py
@@ -122,6 +122,73 @@ 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 node is part of while test's left side.
+ """
+ self.flakes('''
+ def _worker():
+ o = True
+ while o is not True:
+ del o
+ o = False
+ ''')
+
+ def test_delWhileRightSide(self):
+ """
+ Ignore bindings deletion if node is part of while test's right side.
+ """
+ self.flakes('''
+ def _worker():
+ a = False
+ o = True
+ while a == o:
+ 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('''