Skip to content
This repository was archived by the owner on Nov 3, 2023. It is now read-only.

Commit 2549847

Browse files
HanaasagiNurdok
authored andcommitted
fix parsing tuple syntax dunder all (#355)
* fix parse dunder all * update release notes * use better function name * keep line length within 80 * update changelog
1 parent 792b8d9 commit 2549847

File tree

3 files changed

+67
-12
lines changed

3 files changed

+67
-12
lines changed

docs/release_notes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Major Updates
1111

1212
* Support for Python 2.x and PyPy has been dropped (#340).
1313
* Added pre-commit hook (#346)
14+
* Fix parsing tuple syntax ``__all__`` (#355, #352).
1415

1516
3.0.0 - October 14th, 2018
1617
--------------------------

src/pydocstyle/parser.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -444,26 +444,35 @@ def parse_dunder_all(self):
444444
self.dunder_all_error = 'Could not evaluate contents of __all__. '
445445
return
446446
self.consume(tk.OP)
447-
if self.current.value not in '([':
448-
self.dunder_all_error = 'Could not evaluate contents of __all__. '
449-
return
450-
self.consume(tk.OP)
447+
448+
is_surrounded = False
449+
if self.current.value in '([':
450+
is_surrounded = True
451+
self.consume(tk.OP)
451452

452453
dunder_all_content = "("
453-
while self.current.kind != tk.OP or self.current.value not in ")]":
454+
while True:
455+
if is_surrounded and self.current.value in ")]":
456+
break
457+
if self.current.kind in (tk.NEWLINE, tk.ENDMARKER):
458+
break
454459
if self.current.kind in (tk.NL, tk.COMMENT):
455460
pass
456-
elif (self.current.kind == tk.STRING or
457-
self.current.value == ','):
461+
elif (self.current.kind == tk.STRING or self.current.value == ','):
458462
dunder_all_content += self.current.value
459463
else:
460-
self.dunder_all_error = (
461-
'Unexpected token kind in __all__: {!r}. '
462-
.format(self.current.kind))
464+
self.dunder_all_error = 'Could not evaluate contents of __all__.'
463465
return
464466
self.stream.move()
465-
self.consume(tk.OP)
467+
if is_surrounded:
468+
self.consume(tk.OP)
469+
if not is_surrounded and ',' not in dunder_all_content:
470+
self.dunder_all_error = (
471+
'Unexpected token kind in __all__: {!r}. '
472+
.format(self.current.kind))
473+
return
466474
dunder_all_content += ")"
475+
467476
try:
468477
self.dunder_all = eval(dunder_all_content, {})
469478
except BaseException as e:
@@ -472,7 +481,8 @@ def parse_dunder_all(self):
472481
'\bThe value was {}. The exception was:\n{}'
473482
.format(dunder_all_content, e))
474483

475-
while not self.current.kind in self.stream.LOGICAL_NEWLINES:
484+
while (self.current.kind not in self.stream.LOGICAL_NEWLINES and
485+
self.current.kind != tk.ENDMARKER):
476486
if self.current.kind != tk.COMMENT:
477487
self.dunder_all = None
478488
self.dunder_all_error = 'Could not evaluate contents of __all__. '

src/tests/parser_test.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,27 @@ def nested_3(self):
530530
'bar'
531531
]
532532
"""),
533+
CodeSnippet("""\
534+
__all__ = 'foo', 'bar'
535+
"""),
536+
CodeSnippet("""\
537+
__all__ = 'foo', 'bar',
538+
"""),
539+
CodeSnippet(
540+
"""__all__ = 'foo', 'bar'"""
541+
),
542+
CodeSnippet("""\
543+
__all__ = 'foo', \
544+
'bar'
545+
"""),
546+
CodeSnippet("""\
547+
foo = 1
548+
__all__ = 'foo', 'bar'
549+
"""),
550+
CodeSnippet("""\
551+
__all__ = 'foo', 'bar'
552+
foo = 1
553+
"""),
533554
))
534555
def test_dunder_all(code):
535556
"""Test that __all__ is parsed correctly."""
@@ -538,6 +559,29 @@ def test_dunder_all(code):
538559
assert module.dunder_all == ('foo', 'bar')
539560

540561

562+
def test_single_value_dunder_all():
563+
"""Test that single value __all__ is parsed correctly."""
564+
parser = Parser()
565+
code = CodeSnippet("""\
566+
__all__ = 'foo',
567+
""")
568+
module = parser.parse(code, "filepath")
569+
assert module.dunder_all == ('foo', )
570+
571+
code = CodeSnippet("""\
572+
__all__ = 'foo'
573+
""")
574+
module = parser.parse(code, "filepath")
575+
assert module.dunder_all is None
576+
assert module.dunder_all_error
577+
578+
code = CodeSnippet("""\
579+
__all__ = ('foo', )
580+
""")
581+
module = parser.parse(code, "filepath")
582+
assert module.dunder_all == ('foo', )
583+
584+
541585
indeterminable_dunder_all_test_cases = [
542586
CodeSnippet("""\
543587
__all__ = ['foo']

0 commit comments

Comments
 (0)