diff options
author | Anthony Sottile <asottile@umich.edu> | 2019-01-20 16:20:01 -0800 |
---|---|---|
committer | Ian Stapleton Cordasco <graffatcolmingov@gmail.com> | 2019-01-22 18:56:20 -0600 |
commit | 65fdfad26e5213a8245797da3e1368daa63e2067 (patch) | |
tree | fd1210319983f92257235c905eb3136a7d13bbab | |
parent | 14f28ba0279e3547c09b06870f90f01167da08ec (diff) | |
download | pyflakes-65fdfad26e5213a8245797da3e1368daa63e2067.tar.gz |
Fix regression with `__all__ = [not, strings]`
Regression introduced in 47a164136982ea6ef80f302200b2a29d3a4b1c3c
Example trace before fix:
```
...
File "/home/asottile/workspace/pyflakes/pyflakes/checker.py", line 998, in handleNodeStore
binding = ExportBinding(name, node.parent, self.scope)
File "/home/asottile/workspace/pyflakes/pyflakes/checker.py", line 426, in __init__
self.names += ast.literal_eval(source.value)
File "/usr/lib/python3.6/ast.py", line 85, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.6/ast.py", line 61, in _convert
return list(map(_convert, node.elts))
File "/usr/lib/python3.6/ast.py", line 84, in _convert
raise ValueError('malformed node or string: ' + repr(node))
ValueError: malformed node or string: <_ast.Attribute object at 0x7f6d2bf37b70>
```
-rw-r--r-- | pyflakes/checker.py | 12 | ||||
-rw-r--r-- | pyflakes/test/test_imports.py | 27 |
2 files changed, 36 insertions, 3 deletions
diff --git a/pyflakes/checker.py b/pyflakes/checker.py index b8d7be7..650d788 100644 --- a/pyflakes/checker.py +++ b/pyflakes/checker.py @@ -422,21 +422,27 @@ class ExportBinding(Binding): self.names = list(scope['__all__'].names) else: self.names = [] + + def _add_to_names(container): + for node in container.elts: + if isinstance(node, ast.Str): + self.names.append(node.s) + if isinstance(source.value, (ast.List, ast.Tuple)): - self.names += ast.literal_eval(source.value) + _add_to_names(source.value) # If concatenating lists elif isinstance(source.value, ast.BinOp): currentValue = source.value while isinstance(currentValue.right, ast.List): left = currentValue.left right = currentValue.right - self.names += ast.literal_eval(right) + _add_to_names(right) # If more lists are being added if isinstance(left, ast.BinOp): currentValue = left # If just two lists are being added elif isinstance(left, ast.List): - self.names += ast.literal_eval(left) + _add_to_names(left) # All lists accounted for - done break # If not list concatenation diff --git a/pyflakes/test/test_imports.py b/pyflakes/test/test_imports.py index 193f9d3..13e7bef 100644 --- a/pyflakes/test/test_imports.py +++ b/pyflakes/test/test_imports.py @@ -1093,6 +1093,33 @@ class TestSpecialAll(TestCase): __all__ = ['a'] + ['b'] + ['c'] ''', m.UndefinedExport, m.UndefinedExport, m.UndefinedExport, m.UnusedImport) + def test_all_with_attributes(self): + self.flakes(''' + from foo import bar + __all__ = [bar.__name__] + ''') + + def test_all_with_names(self): + # not actually valid, but shouldn't produce a crash + self.flakes(''' + from foo import bar + __all__ = [bar] + ''') + + def test_all_with_attributes_added(self): + self.flakes(''' + from foo import bar + from bar import baz + __all__ = [bar.__name__] + [baz.__name__] + ''') + + def test_all_mixed_attributes_and_strings(self): + self.flakes(''' + from foo import bar + from foo import baz + __all__ = ['bar', baz.__name__] + ''') + def test_unboundExported(self): """ If C{__all__} includes a name which is not bound, a warning is emitted. |