diff options
author | Florent Xicluna <florent.xicluna@gmail.com> | 2014-03-22 15:00:34 +0100 |
---|---|---|
committer | Florent Xicluna <florent.xicluna@gmail.com> | 2014-03-22 15:00:34 +0100 |
commit | f4c674a3a6e80c902147b5bb61ceb176dde0fd4a (patch) | |
tree | 9c98064198b976d1985863ab7fae873d71f7973b | |
parent | e00ab6cf357390651026b74e3b891695b7ea618f (diff) | |
download | pyflakes-f4c674a3a6e80c902147b5bb61ceb176dde0fd4a.tar.gz |
Fix incremental __all__ and tuples in __all__; lp:1241878 and lp:1266446
-rw-r--r-- | pyflakes/checker.py | 35 | ||||
-rw-r--r-- | pyflakes/test/test_imports.py | 17 |
2 files changed, 35 insertions, 17 deletions
diff --git a/pyflakes/checker.py b/pyflakes/checker.py index c695354..7321cec 100644 --- a/pyflakes/checker.py +++ b/pyflakes/checker.py @@ -145,16 +145,16 @@ class ExportBinding(Binding): Names which are imported and not otherwise used but appear in the value of C{__all__} will not have an unused import warning reported for them. """ - def names(self): - """ - Return a list of the names referenced by this binding. - """ - names = [] - if isinstance(self.source, ast.List): - for node in self.source.elts: + def __init__(self, name, source, scope): + if '__all__' in scope and isinstance(source, ast.AugAssign): + self.names = list(scope['__all__'].names) + else: + self.names = [] + if isinstance(source.value, (ast.List, ast.Tuple)): + for node in source.value.elts: if isinstance(node, ast.Str): - names.append(node.s) - return names + self.names.append(node.s) + super(ExportBinding, self).__init__(name, source) class Scope(dict): @@ -309,23 +309,24 @@ class Checker(object): for scope in self.deadScopes: export = isinstance(scope.get('__all__'), ExportBinding) if export: - all = scope['__all__'].names() + all_names = set(scope['__all__'].names) if not scope.importStarred and \ os.path.basename(self.filename) != '__init__.py': # Look for possible mistakes in the export list - undefined = set(all) - set(scope) + undefined = all_names.difference(scope) for name in undefined: self.report(messages.UndefinedExport, scope['__all__'].source, name) else: - all = [] + all_names = [] # Look for imported names that aren't used. for importation in scope.values(): - if isinstance(importation, Importation): - if not importation.used and importation.name not in all: - self.report(messages.UnusedImport, - importation.source, importation.name) + if (isinstance(importation, Importation) and + not importation.used and + importation.name not in all_names): + self.report(messages.UnusedImport, + importation.source, importation.name) def pushScope(self, scopeClass=FunctionScope): self.scopeStack.append(scopeClass()) @@ -500,7 +501,7 @@ class Checker(object): binding = Binding(name, node) elif (parent is not None and name == '__all__' and isinstance(self.scope, ModuleScope)): - binding = ExportBinding(name, parent.value) + binding = ExportBinding(name, parent, self.scope) else: binding = Assignment(name, node) if name in self.scope: diff --git a/pyflakes/test/test_imports.py b/pyflakes/test/test_imports.py index 1f2ef87..76853c7 100644 --- a/pyflakes/test/test_imports.py +++ b/pyflakes/test/test_imports.py @@ -686,6 +686,23 @@ class TestSpecialAll(TestCase): import foo __all__ = ["foo"] ''') + self.flakes(''' + import foo + __all__ = ("foo",) + ''') + + def test_augmentedAssignment(self): + """ + The C{__all__} variable is defined incrementally. + """ + self.flakes(''' + import a + import c + __all__ = ['a'] + __all__ += ['b'] + if 1 < 3: + __all__ += ['c', 'd'] + ''', m.UndefinedExport, m.UndefinedExport) def test_unrecognizable(self): """ |