diff options
author | Phil Frost <indigo@bitglue.com> | 2015-02-14 20:42:06 -0500 |
---|---|---|
committer | Phil Frost <indigo@bitglue.com> | 2015-02-14 20:42:06 -0500 |
commit | 0b1ce4c316d53c9842f2df4ab08856f4f6dc0d83 (patch) | |
tree | 3ac5095aa090a814a729d09f299b5806217c6698 | |
parent | 8f539dfc70e88af5c287c898799f9bd1aae6512d (diff) | |
parent | 84b7dd63a379b30968f028a0346ec1958c82fbbe (diff) | |
download | pyflakes-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.py | 18 | ||||
-rw-r--r-- | pyflakes/test/test_undefined_names.py | 68 |
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(''' |