diff options
author | Adi Roiban <adi.roiban@chevah.com> | 2015-02-14 11:00:57 +0000 |
---|---|---|
committer | Adi Roiban <adi.roiban@chevah.com> | 2015-02-14 11:06:33 +0000 |
commit | 4bfe6751b4b9b40013cab29769b9c4712558669e (patch) | |
tree | 6fc23c2d43d4e6c7c2c11bea6246bcdc2c3c1798 | |
parent | 8dd58c955cda639ae9155fd42b3c69eca47f5a6c (diff) | |
download | pyflakes-4bfe6751b4b9b40013cab29769b9c4712558669e.tar.gz |
Update del handling in if and while statements.
-rw-r--r-- | pyflakes/checker.py | 38 | ||||
-rw-r--r-- | pyflakes/test/test_undefined_names.py | 67 |
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(''' |