Skip to content

Commit d1e5923

Browse files
author
whitequark
committedMay 9, 2015
Add Python 3.0-3.1 support.
1 parent b4d5653 commit d1e5923

File tree

4 files changed

+862
-262
lines changed

4 files changed

+862
-262
lines changed
 

Diff for: ‎pyparser/ast.py

+76-21
Original file line numberDiff line numberDiff line change
@@ -94,23 +94,38 @@ class alias(AST, commonloc):
9494
_fields = ('name', 'asname')
9595
_locs = commonloc._locs + ('name_loc', 'as_loc', 'asname_loc')
9696

97+
class arg(AST, commonloc):
98+
"""
99+
A formal argument, e.g. in ``def f(x)`` or ``def f(x: T)``.
100+
101+
:ivar arg: (string) argument name
102+
:ivar annotation: (node) type annotation, if any; **emitted since 3.0**
103+
:ivar arg_loc: location of argument name
104+
:ivar colon_loc: location of ``:``, if any; **emitted since 3.0**
105+
"""
106+
_fields = ('arg', 'annotation')
107+
_locs = commonloc._locs + ('arg_loc', 'colon_loc')
108+
97109
class arguments(AST, beginendloc):
98110
"""
99111
Function definition arguments, e.g. in ``def f(x, y=1, *z, **t)``.
100112
101-
:ivar args: (list of assignable node) regular formal arguments
102-
:ivar vararg: (string) splat formal argument (if any), e.g. in ``*x``
103-
:ivar kwarg: (string) keyword splat formal argument (if any), e.g. in ``**x``
113+
:ivar args: (list of :class:`arg`) regular formal arguments
104114
:ivar defaults: (list of node) values of default arguments
115+
:ivar vararg: (:class:`arg`) splat formal argument (if any), e.g. in ``*x``
116+
:ivar kwonlyargs: (list of :class:`arg`) keyword-only (post-*) formal arguments;
117+
**emitted since 3.0**
118+
:ivar kw_defaults: (list of node) values of default keyword-only arguments;
119+
**emitted since 3.0**
120+
:ivar kwarg: (:class:`arg`) keyword splat formal argument (if any), e.g. in ``**x``
105121
:ivar star_loc: location of ``*``, if any
106-
:ivar vararg_loc: location of splat formal argument, if any
107122
:ivar dstar_loc: location of ``**``, if any
108-
:ivar kwarg_loc: location of keyword splat formal argument, if any
109123
:ivar equals_locs: locations of ``=``
124+
:ivar kw_equals_locs: locations of ``=`` of default keyword-only arguments;
125+
**emitted since 3.0**
110126
"""
111-
_fields = ('args', 'vararg', 'kwarg', 'defaults')
112-
_locs = beginendloc._locs + ('star_loc', 'vararg_loc', 'dstar_loc',
113-
'vararg_loc', 'kwarg_loc', 'equals_locs')
127+
_fields = ('args', 'vararg', 'kwonlyargs', 'kwarg', 'defaults', 'kw_defaults')
128+
_locs = beginendloc._locs + ('star_loc', 'dstar_loc', 'equals_locs', 'kw_equals_locs')
114129

115130
class boolop(AST, commonloc):
116131
"""
@@ -255,6 +270,8 @@ class DictComp(expr, beginendloc):
255270
"""
256271
_fields = ('key', 'value', 'generators')
257272
_locs = beginendloc._locs + ('colon_loc',)
273+
class Ellipsis(expr):
274+
"""The ellipsis, e.g. in ``x[...]``."""
258275
class GeneratorExp(expr, beginendloc):
259276
"""
260277
A generator expression, e.g. ``(x for x in y)``.
@@ -308,6 +325,13 @@ class Name(expr):
308325
:ivar id: (string) name
309326
"""
310327
_fields = ('id', 'ctx')
328+
class NameConstant(expr):
329+
"""
330+
A named constant, e.g. ``None``.
331+
332+
:ivar value: Python value, one of ``None``, ``True`` or ``False``
333+
"""
334+
_fields = ('value',)
311335
class Num(expr):
312336
"""
313337
An integer, floating point or complex number, e.g. ``1``, ``1.0`` or ``1.0j``.
@@ -350,6 +374,15 @@ class Str(expr, beginendloc):
350374
:ivar s: (string) value
351375
"""
352376
_fields = ('s',)
377+
class Starred(expr):
378+
"""
379+
A starred expression, e.g. ``*x`` in ``*x, y = z``.
380+
381+
:ivar value: (node) expression
382+
:ivar star_loc: location of ``*``
383+
"""
384+
_fields = ('value',)
385+
_locs = expr._locs + ('star_loc',)
353386
class Subscript(expr, beginendloc):
354387
"""
355388
A subscript operation, e.g. ``x[1]``.
@@ -441,8 +474,6 @@ class Sub(operator):
441474

442475
class slice(AST, commonloc):
443476
"""Base class for slice operations."""
444-
class Ellipsis(slice):
445-
"""The ellipsis, e.g. in ``x[...]``."""
446477
class ExtSlice(slice):
447478
"""
448479
The multiple slice, e.g. in ``x[0:1, 2:3]``.
@@ -503,21 +534,28 @@ class Break(stmt, keywordloc):
503534
"""The ``break`` statement."""
504535
class ClassDef(stmt, keywordloc):
505536
"""
506-
The ``class x(z, y):· t`` statement.
537+
The ``class x(z, y):· t`` (2.6) or
538+
``class x(y, z=1, *t, **u):· v`` (3.0) statement.
507539
508540
:ivar name: (string) name
509541
:ivar bases: (list of node) base classes
542+
:ivar keywords: (list of :class:`keyword`) keyword arguments; **emitted since 3.0**
543+
:ivar starargs: (node) splat argument (if any), e.g. in ``*x``; **emitted since 3.0**
544+
:ivar kwargs: (node) keyword splat argument (if any), e.g. in ``**x``; **emitted since 3.0**
510545
:ivar body: (list of node) body
511546
:ivar decorator_list: (list of node) decorators
512547
:ivar keyword_loc: location of ``class``
513548
:ivar name_loc: location of name
514549
:ivar lparen_loc: location of ``(``, if any
550+
:ivar star_loc: location of ``*``, if any; **emitted since 3.0**
551+
:ivar dstar_loc: location of ``**``, if any; **emitted since 3.0**
515552
:ivar rparen_loc: location of ``)``, if any
516553
:ivar colon_loc: location of ``:``
517554
:ivar at_locs: locations of decorator ``@``
518555
"""
519-
_fields = ('name', 'bases', 'body', 'decorator_list')
520-
_locs = keywordloc._locs + ('name_loc', 'lparen_loc', 'rparen_loc', 'colon_loc', 'at_locs')
556+
_fields = ('name', 'bases', 'keywords', 'starargs', 'kwargs', 'body', 'decorator_list')
557+
_locs = keywordloc._locs + ('name_loc', 'lparen_loc', 'star_loc', 'dstar_loc', 'rparen_loc',
558+
'colon_loc', 'at_locs')
521559
class Continue(stmt, keywordloc):
522560
"""The ``continue`` statement."""
523561
class Delete(stmt, keywordloc):
@@ -566,19 +604,21 @@ class For(stmt, keywordloc):
566604
_locs = keywordloc._locs + ('in_loc', 'for_colon_loc', 'else_loc', 'else_colon_loc')
567605
class FunctionDef(stmt, keywordloc):
568606
"""
569-
The ``def f(x):· y`` statement.
607+
The ``def f(x):· y`` (2.6) or ``def f(x) -> t:· y`` (2.6) statement.
570608
571609
:ivar name: (string) name
572610
:ivar args: (:class:`arguments`) formal arguments
611+
:ivar returns: (node) return type annotation; **emitted since 3.0**
573612
:ivar body: (list of node) body
574613
:ivar decorator_list: (list of node) decorators
575614
:ivar keyword_loc: location of ``def``
576615
:ivar name_loc: location of name
616+
:ivar arrow_loc: location of ``->``, if any; **emitted since 3.0**
577617
:ivar colon_loc: location of ``:``, if any
578618
:ivar at_locs: locations of decorator ``@``
579619
"""
580-
_fields = ('name', 'args', 'body', 'decorator_list')
581-
_locs = keywordloc._locs + ('name_loc', 'colon_loc', 'at_locs')
620+
_fields = ('name', 'args', 'returns', 'body', 'decorator_list')
621+
_locs = keywordloc._locs + ('name_loc', 'arrow_loc', 'colon_loc', 'at_locs')
582622
class Global(stmt, keywordloc):
583623
"""
584624
The ``global x, y`` statement.
@@ -625,6 +665,17 @@ class ImportFrom(stmt, keywordloc):
625665
"""
626666
_fields = ('names', 'module', 'level')
627667
_locs = keywordloc._locs + ('dots_loc', 'module_loc', 'import_loc', 'lparen_loc', 'rparen_loc')
668+
class Nonlocal(stmt, keywordloc):
669+
"""
670+
The ``nonlocal x, y`` statement.
671+
672+
**Emitted since 3.0.**
673+
674+
:ivar names: (list of string) names
675+
:ivar name_locs: locations of names
676+
"""
677+
_fields = ('names',)
678+
_locs = keywordloc._locs + ('name_locs',)
628679
class Pass(stmt, keywordloc):
629680
"""The ``pass`` statement."""
630681
class Print(stmt, keywordloc):
@@ -642,13 +693,17 @@ class Print(stmt, keywordloc):
642693
_locs = keywordloc._locs + ('dest_loc',)
643694
class Raise(stmt, keywordloc):
644695
"""
645-
The ``raise exn, arg, traceback`` statement.
696+
The ``raise exc, arg, traceback`` (2.x) or
697+
or ``raise exc from cause`` (3.0) statement.
646698
647-
:ivar type: (node) exception type or instance
648-
:ivar inst: (node) exception instance or argument list, if any
649-
:ivar tback: (node) traceback, if any
699+
:ivar exc: (node) exception type or instance
700+
:ivar cause: (node) cause of exception, if any; **emitted since 3.0**
701+
:ivar inst: (node) exception instance or argument list, if any; **emitted until 3.0**
702+
:ivar tback: (node) traceback, if any; **emitted until 3.0**
703+
:ivar from_loc: location of ``from``, if any; **emitted since 3.0**
650704
"""
651-
_fields = ('type', 'inst', 'tback')
705+
_fields = ('exc', 'cause', 'inst', 'tback')
706+
_locs = keywordloc._locs + ('from_loc',)
652707
class Return(stmt, keywordloc):
653708
"""
654709
The ``return x`` statement.

Diff for: ‎pyparser/coverage/__init__.py

+22-7
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ def instrument():
6464
in_square -= 1
6565

6666
if token.kind in ('def', 'if', 'elif', 'else', 'for') and in_square == 0:
67+
if token.kind == 'def':
68+
ident = lex.next()
69+
if ident.value[0] == '_':
70+
stmt_stack.append(None)
71+
continue
6772
all_stmt_list.append((token.loc.begin_pos, token.loc.end_pos))
6873
stmt_stack.append("_all_stmts[(%d,%d)] = True\n" %
6974
(token.loc.begin_pos, token.loc.end_pos))
@@ -82,25 +87,35 @@ def instrument():
8287

8388
# Produce an HTML report for test coverage of parser rules.
8489
def report(parser, name='parser'):
85-
rewriter = source.Rewriter(_buf)
86-
total_pts = 0
87-
total_covered = 0
90+
all_locs = dict()
8891
for rule in parser._all_rules:
8992
pts = len(rule.covered)
9093
covered = len(list(filter(lambda x: x, rule.covered)))
94+
if rule.loc in all_locs:
95+
pts_, covered_ = all_locs[rule.loc]
96+
if covered > covered_:
97+
all_locs[rule.loc] = pts, covered
98+
else:
99+
all_locs[rule.loc] = pts, covered
100+
101+
rewriter = source.Rewriter(_buf)
102+
total_pts = 0
103+
total_covered = 0
104+
for loc in all_locs:
105+
pts, covered = all_locs[loc]
91106
if covered == 0:
92107
klass, hint = 'uncovered', None
93108
elif covered < pts:
94109
klass, hint = 'partial', ', '.join(map(lambda x: "yes" if x else "no", rule.covered))
95110
else:
96111
klass, hint = 'covered', None
97112

98-
loc = source.Range(_buf, *rule.loc)
113+
sloc = source.Range(_buf, *rule.loc)
99114
if hint:
100-
rewriter.insert_before(loc, r"<span class='%s' title='%s'>" % (klass, hint))
115+
rewriter.insert_before(sloc, r"<span class='%s' title='%s'>" % (klass, hint))
101116
else:
102-
rewriter.insert_before(loc, r"<span class='%s'>" % klass)
103-
rewriter.insert_after(loc, r"</span>")
117+
rewriter.insert_before(sloc, r"<span class='%s'>" % klass)
118+
rewriter.insert_after(sloc, r"</span>")
104119

105120
total_pts += pts
106121
total_covered += covered

Diff for: ‎pyparser/parser.py

+487-156
Large diffs are not rendered by default.

Diff for: ‎pyparser/test/test_parser.py

+277-78
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ class ParserTestCase(unittest.TestCase):
1515

1616
maxDiff = None
1717

18-
versions = [(2, 6), (2, 7)]
18+
versions = [(2, 6), (2, 7), (3, 0), (3, 1)]
1919

2020
def parser_for(self, code, version, interactive=False):
2121
code = code.replace("·", "\n")
2222

23-
self.source_buffer = source.Buffer(code)
23+
self.source_buffer = source.Buffer(code, str(version))
2424
self.lexer = lexer.Lexer(self.source_buffer, version, interactive=interactive)
2525

2626
old_next = self.lexer.next
@@ -123,14 +123,15 @@ def assertParsesGen(self, expected_flat_ast, code,
123123

124124
ast = self.parser_for(code + "\n", version).file_input()
125125
flat_ast = self.flatten_ast(ast)
126-
python_ast = pyast.parse(code.replace("·", "\n") + "\n")
127-
flat_python_ast = self.flatten_python_ast(python_ast)
128126
self.assertEqual({'ty': 'Module', 'body': expected_flat_ast},
129127
flat_ast)
130-
if validate_if():
128+
self.match_loc(ast, loc_matcher, ast_slicer)
129+
130+
if version == sys.version_info[0:2] and validate_if():
131+
python_ast = pyast.parse(code.replace("·", "\n") + "\n")
132+
flat_python_ast = self.flatten_python_ast(python_ast)
131133
self.assertEqual({'ty': 'Module', 'body': expected_flat_ast},
132134
flat_python_ast)
133-
self.match_loc(ast, loc_matcher, ast_slicer)
134135

135136
def assertParsesSuite(self, expected_flat_ast, code, loc_matcher="", **kwargs):
136137
self.assertParsesGen(expected_flat_ast, code,
@@ -155,8 +156,12 @@ def assertParsesToplevel(self, expected_flat_ast, code,
155156
ast = getattr(self.parser_for(code, version=version, interactive=interactive), mode)()
156157
self.assertEqual(expected_flat_ast, self.flatten_ast(ast))
157158

158-
def assertDiagnoses(self, code, level, reason, args={}, loc_matcher=""):
159+
def assertDiagnoses(self, code, level, reason, args={}, loc_matcher="",
160+
only_if=lambda ver: True):
159161
for version in self.versions:
162+
if not only_if(version):
163+
continue
164+
160165
try:
161166
self.parser_for(code, version).file_input()
162167
self.fail("Expected a diagnostic")
@@ -170,7 +175,8 @@ def assertDiagnoses(self, code, level, reason, args={}, loc_matcher=""):
170175
self.match_loc([e.diagnostic.location] + e.diagnostic.highlights,
171176
loc_matcher)
172177

173-
def assertDiagnosesUnexpected(self, code, err_token, loc_matcher=""):
178+
def assertDiagnosesUnexpected(self, code, err_token, loc_matcher="",
179+
only_if=lambda ver: True):
174180
self.assertDiagnoses(code,
175181
"fatal", "unexpected {actual}: expected {expected}",
176182
{'actual': err_token}, loc_matcher="")
@@ -190,6 +196,11 @@ def assertDiagnosesUnexpected(self, code, err_token, loc_matcher=""):
190196
ast_z = {'ty': 'Name', 'id': 'z', 'ctx': None}
191197
ast_t = {'ty': 'Name', 'id': 't', 'ctx': None}
192198

199+
ast_arg_x = {'ty': 'arg', 'arg': 'x', 'annotation': None}
200+
ast_arg_y = {'ty': 'arg', 'arg': 'y', 'annotation': None}
201+
ast_arg_z = {'ty': 'arg', 'arg': 'z', 'annotation': None}
202+
ast_arg_t = {'ty': 'arg', 'arg': 't', 'annotation': None}
203+
193204
#
194205
# LITERALS
195206
#
@@ -233,6 +244,25 @@ def test_ident(self):
233244
"foo",
234245
"~~~ loc")
235246

247+
def test_named(self):
248+
self.assertParsesExpr(
249+
{'ty': 'NameConstant', 'value': None},
250+
"None",
251+
"~~~~ loc",
252+
only_if=lambda ver: ver >= (3, 0))
253+
254+
self.assertParsesExpr(
255+
{'ty': 'NameConstant', 'value': True},
256+
"True",
257+
"~~~~ loc",
258+
only_if=lambda ver: ver >= (3, 0))
259+
260+
self.assertParsesExpr(
261+
{'ty': 'NameConstant', 'value': False},
262+
"False",
263+
"~~~~~ loc",
264+
only_if=lambda ver: ver >= (3, 0))
265+
236266
#
237267
# OPERATORS
238268
#
@@ -378,7 +408,8 @@ def test_compare(self):
378408
'left': self.ast_1, 'comparators': [self.ast_1]},
379409
"1 <> 1",
380410
"~~~~~~ loc"
381-
" ~~ ops.0.loc")
411+
" ~~ ops.0.loc",
412+
only_if=lambda ver: ver < (3, 0))
382413

383414
self.assertParsesExpr(
384415
{'ty': 'Compare', 'ops': [{'ty': 'In'}],
@@ -550,7 +581,8 @@ def test_repr(self):
550581
"`1`",
551582
"^ begin_loc"
552583
" ^ end_loc"
553-
"~~~ loc")
584+
"~~~ loc",
585+
only_if=lambda ver: ver < (3, 0))
554586

555587
#
556588
# GENERATOR AND CONDITIONAL EXPRESSIONS
@@ -639,29 +671,46 @@ def test_lambda(self):
639671
self.assertParsesExpr(
640672
{'ty': 'Lambda',
641673
'args': {'ty': 'arguments', 'args': [], 'defaults': [],
674+
'kwonlyargs': [], 'kw_defaults': [],
642675
'kwarg': None, 'vararg': None},
643676
'body': self.ast_x},
644677
"lambda: x",
645678
"~~~~~~ lambda_loc"
646679
" < args.loc"
647680
" ^ colon_loc"
648-
"~~~~~~~~~ loc")
681+
"~~~~~~~~~ loc",
682+
validate_if=lambda: sys.version_info >= (3, 2))
649683

650-
def test_old_lambda(self):
684+
def test_lambda_nocond(self):
651685
self.assertParsesExpr(
652-
{'ty': 'ListComp', 'elt': self.ast_x, 'generators': [
686+
{'ty': 'GeneratorExp', 'elt': self.ast_x, 'generators': [
653687
{'ty': 'comprehension', 'iter': self.ast_z, 'target': self.ast_y,
654688
'ifs': [{'ty': 'Lambda',
655689
'args': {'ty': 'arguments', 'args': [], 'defaults': [],
690+
'kwonlyargs': [], 'kw_defaults': [],
656691
'kwarg': None, 'vararg': None},
657692
'body': self.ast_t}
658693
]}
659694
]},
660-
"[x for y in z if lambda: t]",
695+
"(x for y in z if lambda: t)",
661696
" ~~~~~~ generators.0.ifs.0.lambda_loc"
662697
" < generators.0.ifs.0.args.loc"
663698
" ^ generators.0.ifs.0.colon_loc"
664-
" ~~~~~~~~~ generators.0.ifs.0.loc")
699+
" ~~~~~~~~~ generators.0.ifs.0.loc",
700+
validate_if=lambda: sys.version_info >= (3, 2))
701+
702+
self.assertParsesExpr(
703+
{'ty': 'GeneratorExp', 'elt': self.ast_x, 'generators': [
704+
{'ty': 'comprehension', 'iter': self.ast_z, 'target': self.ast_y,
705+
'ifs': [{'ty': 'Lambda',
706+
'args': {'ty': 'arguments', 'args': [self.ast_arg_t], 'defaults': [],
707+
'kwonlyargs': [], 'kw_defaults': [],
708+
'kwarg': None, 'vararg': None},
709+
'body': self.ast_t}
710+
]}
711+
]},
712+
"(x for y in z if lambda t: t)",
713+
validate_if=lambda: sys.version_info >= (3, 2))
665714

666715
#
667716
# CALLS, ATTRIBUTES AND SUBSCRIPTS
@@ -704,31 +753,41 @@ def test_call(self):
704753
'args': [], 'keywords': []},
705754
"x(*y)",
706755
" ^ star_loc"
707-
"~~~~~ loc")
756+
"~~~~~ loc",
757+
# This and following tests fail because of a grammar bug (conflict)
758+
# in upstream Python. We get different results because our parsers
759+
# are different, and upstream works more or less by accident.
760+
# Upstream "fixed" it with a gross workaround in a minor version
761+
# (at least 3.1.5).
762+
# Not really worth fixing for us, so skip.
763+
only_if=lambda ver: ver not in ((3, 0), (3, 1)))
708764

709765
self.assertParsesExpr(
710766
{'ty': 'Call', 'func': self.ast_x, 'starargs': self.ast_y, 'kwargs': self.ast_z,
711767
'args': [], 'keywords': []},
712768
"x(*y, **z)",
713769
" ^ star_loc"
714770
" ^^ dstar_loc"
715-
"~~~~~~~~~~ loc")
771+
"~~~~~~~~~~ loc",
772+
only_if=lambda ver: ver not in ((3, 0), (3, 1)))
716773

717774
self.assertParsesExpr(
718775
{'ty': 'Call', 'func': self.ast_x, 'starargs': self.ast_y, 'kwargs': self.ast_z,
719776
'args': [], 'keywords': [{'ty': 'keyword', 'arg': 't', 'value': self.ast_t}]},
720777
"x(*y, t=t, **z)",
721778
" ^ star_loc"
722779
" ^^ dstar_loc"
723-
"~~~~~~~~~~~~~~~ loc")
780+
"~~~~~~~~~~~~~~~ loc",
781+
only_if=lambda ver: ver not in ((3, 0), (3, 1)))
724782

725783
self.assertParsesExpr(
726784
{'ty': 'Call', 'func': self.ast_x, 'starargs': self.ast_z, 'kwargs': self.ast_t,
727785
'args': [self.ast_y], 'keywords': []},
728786
"x(y, *z, **t)",
729787
" ^ star_loc"
730788
" ^^ dstar_loc"
731-
"~~~~~~~~~~~~~ loc")
789+
"~~~~~~~~~~~~~ loc",
790+
only_if=lambda ver: ver not in ((3, 0), (3, 1)))
732791

733792
self.assertParsesExpr(
734793
{'ty': 'Call', 'func': self.ast_x, 'starargs': None, 'kwargs': self.ast_z,
@@ -808,7 +867,7 @@ def test_subscript(self):
808867
" ~~~~ slice.loc"
809868
"~~~~~~~ loc",
810869
# A Python bug places ast.Name(id='None') instead of None in step on <3.0
811-
validate_if=lambda: sys.version_info[0] > 2)
870+
validate_if=lambda: sys.version_info >= (3, 0))
812871

813872
self.assertParsesExpr(
814873
{'ty': 'Subscript', 'value': self.ast_x, 'ctx': None,
@@ -824,7 +883,16 @@ def test_subscript(self):
824883
'slice': {'ty': 'Ellipsis'}},
825884
"x[...]",
826885
" ~~~ slice.loc"
827-
"~~~~~~ loc")
886+
"~~~~~~ loc",
887+
only_if=lambda ver: ver < (3, 0))
888+
889+
self.assertParsesExpr(
890+
{'ty': 'Subscript', 'value': self.ast_x, 'ctx': None,
891+
'slice': {'ty': 'Index', 'value': {'ty': 'Ellipsis'}}},
892+
"x[...]",
893+
" ~~~ slice.loc"
894+
"~~~~~~ loc",
895+
only_if=lambda ver: ver >= (3, 0))
828896

829897
def test_attribute(self):
830898
self.assertParsesExpr(
@@ -866,6 +934,16 @@ def test_assign_tuplerhs(self):
866934
" ~~~~ 0.value.loc"
867935
"~~~~~~~~ 0.loc")
868936

937+
def test_assign_starred(self):
938+
self.assertParsesSuite(
939+
[{'ty': 'Assign', 'targets': [{'ty': 'Starred', 'value': self.ast_x}],
940+
'value': self.ast_y}],
941+
"*x = y",
942+
"^ 0.targets.0.star_loc"
943+
"~~ 0.targets.0.loc"
944+
"~~~~~~ 0.loc",
945+
only_if=lambda ver: ver >= (3, 0))
946+
869947
def test_augassign(self):
870948
self.assertParsesSuite(
871949
[{'ty': 'AugAssign', 'op': {'ty': 'Add'}, 'target': self.ast_x, 'value': self.ast_1}],
@@ -950,27 +1028,31 @@ def test_print(self):
9501028
[{'ty': 'Print', 'dest': None, 'values': [self.ast_1], 'nl': True}],
9511029
"print 1",
9521030
"~~~~~ 0.keyword_loc"
953-
"~~~~~~~ 0.loc")
1031+
"~~~~~~~ 0.loc",
1032+
only_if=lambda ver: ver < (3, 0))
9541033

9551034
self.assertParsesSuite(
9561035
[{'ty': 'Print', 'dest': None, 'values': [self.ast_1], 'nl': False}],
9571036
"print 1,",
9581037
"~~~~~ 0.keyword_loc"
959-
"~~~~~~~~ 0.loc")
1038+
"~~~~~~~~ 0.loc",
1039+
only_if=lambda ver: ver < (3, 0))
9601040

9611041
self.assertParsesSuite(
9621042
[{'ty': 'Print', 'dest': self.ast_2, 'values': [self.ast_1], 'nl': True}],
9631043
"print >>2, 1",
9641044
"~~~~~ 0.keyword_loc"
9651045
" ~~ 0.dest_loc"
966-
"~~~~~~~~~~~~ 0.loc")
1046+
"~~~~~~~~~~~~ 0.loc",
1047+
only_if=lambda ver: ver < (3, 0))
9671048

9681049
self.assertParsesSuite(
9691050
[{'ty': 'Print', 'dest': self.ast_2, 'values': [self.ast_1], 'nl': False}],
9701051
"print >>2, 1,",
9711052
"~~~~~ 0.keyword_loc"
9721053
" ~~ 0.dest_loc"
973-
"~~~~~~~~~~~~~ 0.loc")
1054+
"~~~~~~~~~~~~~ 0.loc",
1055+
only_if=lambda ver: ver < (3, 0))
9741056

9751057
def test_del(self):
9761058
self.assertParsesSuite(
@@ -1029,28 +1111,48 @@ def test_yield(self):
10291111

10301112
def test_raise(self):
10311113
self.assertParsesSuite(
1032-
[{'ty': 'Raise', 'type': None, 'inst': None, 'tback': None}],
1114+
[{'ty': 'Raise', 'exc': None, 'inst': None,
1115+
'tback': None, 'cause': None}],
10331116
"raise",
10341117
"~~~~~ 0.keyword_loc"
1035-
"~~~~~ 0.loc")
1118+
"~~~~~ 0.loc",
1119+
validate_if=lambda: False)
10361120

10371121
self.assertParsesSuite(
1038-
[{'ty': 'Raise', 'type': self.ast_x, 'inst': None, 'tback': None}],
1122+
[{'ty': 'Raise', 'exc': self.ast_x, 'inst': None,
1123+
'tback': None, 'cause': None}],
10391124
"raise x",
10401125
"~~~~~ 0.keyword_loc"
1041-
"~~~~~~~ 0.loc")
1126+
"~~~~~~~ 0.loc",
1127+
validate_if=lambda: False)
10421128

10431129
self.assertParsesSuite(
1044-
[{'ty': 'Raise', 'type': self.ast_x, 'inst': self.ast_y, 'tback': None}],
1130+
[{'ty': 'Raise', 'exc': self.ast_x, 'inst': self.ast_y,
1131+
'tback': None, 'cause': None}],
10451132
"raise x, y",
10461133
"~~~~~ 0.keyword_loc"
1047-
"~~~~~~~~~~ 0.loc")
1134+
"~~~~~~~~~~ 0.loc",
1135+
only_if=lambda ver: ver < (3, 0),
1136+
validate_if=lambda: False)
10481137

10491138
self.assertParsesSuite(
1050-
[{'ty': 'Raise', 'type': self.ast_x, 'inst': self.ast_y, 'tback': self.ast_z}],
1139+
[{'ty': 'Raise', 'exc': self.ast_x, 'inst': self.ast_y,
1140+
'tback': self.ast_z, 'cause': None}],
10511141
"raise x, y, z",
10521142
"~~~~~ 0.keyword_loc"
1053-
"~~~~~~~~~~~~~ 0.loc")
1143+
"~~~~~~~~~~~~~ 0.loc",
1144+
only_if=lambda ver: ver < (3, 0),
1145+
validate_if=lambda: False)
1146+
1147+
self.assertParsesSuite(
1148+
[{'ty': 'Raise', 'exc': self.ast_x, 'inst': None,
1149+
'tback': None, 'cause': self.ast_y}],
1150+
"raise x from y",
1151+
"~~~~~ 0.keyword_loc"
1152+
" ~~~~ 0.from_loc"
1153+
"~~~~~~~~~~~~~~ 0.loc",
1154+
only_if=lambda ver: ver >= (3, 0),
1155+
validate_if=lambda: False)
10541156

10551157
def test_import(self):
10561158
self.assertParsesSuite(
@@ -1149,6 +1251,14 @@ def test_from(self):
11491251
" ~~ 0.dots_loc"
11501252
"~~~~~~~~~~~~~~~~~~ 0.loc")
11511253

1254+
self.assertParsesSuite(
1255+
[{'ty': 'ImportFrom', 'names': [
1256+
{'ty': 'alias', 'name': 'foo', 'asname': None}
1257+
], 'module': None, 'level': 3}],
1258+
"from ... import foo",
1259+
" ~~~ 0.dots_loc"
1260+
"~~~~~~~~~~~~~~~~~~~ 0.loc")
1261+
11521262
def test_global(self):
11531263
self.assertParsesSuite(
11541264
[{'ty': 'Global', 'names': ['x', 'y']}],
@@ -1158,26 +1268,39 @@ def test_global(self):
11581268
" ^ 0.name_locs.1"
11591269
"~~~~~~~~~~~ 0.loc")
11601270

1271+
def test_nonlocal(self):
1272+
self.assertParsesSuite(
1273+
[{'ty': 'Nonlocal', 'names': ['x', 'y']}],
1274+
"nonlocal x, y",
1275+
"~~~~~~~~ 0.keyword_loc"
1276+
" ^ 0.name_locs.0"
1277+
" ^ 0.name_locs.1"
1278+
"~~~~~~~~~~~~~ 0.loc",
1279+
only_if=lambda ver: ver >= (3, 0))
1280+
11611281
def test_exec(self):
11621282
self.assertParsesSuite(
11631283
[{'ty': 'Exec', 'body': self.ast_1, 'globals': None, 'locals': None}],
11641284
"exec 1",
11651285
"~~~~ 0.keyword_loc"
1166-
"~~~~~~ 0.loc")
1286+
"~~~~~~ 0.loc",
1287+
only_if=lambda ver: ver < (3, 0))
11671288

11681289
self.assertParsesSuite(
11691290
[{'ty': 'Exec', 'body': self.ast_1, 'globals': self.ast_2, 'locals': None}],
11701291
"exec 1 in 2",
11711292
"~~~~ 0.keyword_loc"
11721293
" ~~ 0.in_loc"
1173-
"~~~~~~~~~~~ 0.loc")
1294+
"~~~~~~~~~~~ 0.loc",
1295+
only_if=lambda ver: ver < (3, 0))
11741296

11751297
self.assertParsesSuite(
11761298
[{'ty': 'Exec', 'body': self.ast_1, 'globals': self.ast_2, 'locals': self.ast_3}],
11771299
"exec 1 in 2, 3",
11781300
"~~~~ 0.keyword_loc"
11791301
" ~~ 0.in_loc"
1180-
"~~~~~~~~~~~~~~ 0.loc")
1302+
"~~~~~~~~~~~~~~ 0.loc",
1303+
only_if=lambda ver: ver < (3, 0))
11811304

11821305
def test_assert(self):
11831306
self.assertParsesSuite(
@@ -1304,7 +1427,8 @@ def test_try(self):
13041427
'body': [self.ast_expr_2]}
13051428
]}],
13061429
"try:· 1·except y, t:· 2",
1307-
" ^ 0.handlers.0.as_loc")
1430+
" ^ 0.handlers.0.as_loc",
1431+
only_if=lambda ver: ver < (3, 0))
13081432

13091433
self.assertParsesSuite(
13101434
[{'ty': 'TryExcept', 'body': [self.ast_expr_1], 'orelse': [self.ast_expr_3],
@@ -1376,81 +1500,97 @@ def test_with(self):
13761500
" ~~~~~~ 0.items.0.loc"
13771501
" ~ 0.items.1.loc"
13781502
"~~~~~~~~~~~~~~~~~~~ 0.loc",
1379-
only_if=lambda ver: ver >= (2, 7),
1503+
only_if=lambda ver: ver == (2, 7) or ver >= (3, 1),
13801504
validate_if=lambda: sys.version_info >= (3, 0))
13811505

13821506
def test_class(self):
13831507
self.assertParsesSuite(
13841508
[{'ty': 'ClassDef', 'name': 'x', 'bases': [],
1509+
'keywords': [], 'starargs': None, 'kwargs': None,
13851510
'body': [{'ty': 'Pass'}], 'decorator_list': []}],
13861511
"class x:· pass",
13871512
"~~~~~ 0.keyword_loc"
13881513
" ^ 0.name_loc"
13891514
" ^ 0.colon_loc"
1390-
"~~~~~~~~~~~~~~~ 0.loc")
1515+
"~~~~~~~~~~~~~~~ 0.loc",
1516+
validate_if=lambda: sys.version_info >= (3, 0))
13911517

13921518
self.assertParsesSuite(
13931519
[{'ty': 'ClassDef', 'name': 'x', 'bases': [self.ast_y, self.ast_z],
1520+
'keywords': [], 'starargs': None, 'kwargs': None,
13941521
'body': [{'ty': 'Pass'}], 'decorator_list': []}],
13951522
"class x(y, z):· pass",
13961523
" ^ 0.lparen_loc"
13971524
" ^ 0.rparen_loc"
1398-
"~~~~~~~~~~~~~~~~~~~~~ 0.loc")
1525+
"~~~~~~~~~~~~~~~~~~~~~ 0.loc",
1526+
validate_if=lambda: sys.version_info >= (3, 0))
13991527

14001528
def test_func(self):
14011529
self.assertParsesSuite(
14021530
[{'ty': 'FunctionDef', 'name': 'foo',
14031531
'args': {'ty': 'arguments', 'args': [], 'defaults': [],
1532+
'kwonlyargs': [], 'kw_defaults': [],
14041533
'kwarg': None, 'vararg': None},
1534+
'returns': None,
14051535
'body': [{'ty': 'Pass'}], 'decorator_list': []}],
14061536
"def foo():· pass",
14071537
"~~~ 0.keyword_loc"
14081538
" ~~~ 0.name_loc"
14091539
" ^ 0.args.begin_loc"
14101540
" ^ 0.args.end_loc"
14111541
" ^ 0.colon_loc"
1412-
"~~~~~~~~~~~~~~~~~ 0.loc")
1542+
"~~~~~~~~~~~~~~~~~ 0.loc",
1543+
validate_if=lambda: sys.version_info >= (3, 2))
14131544

14141545
def test_decorated(self):
14151546
self.assertParsesSuite(
14161547
[{'ty': 'ClassDef', 'name': 'x', 'bases': [],
1548+
'keywords': [], 'starargs': None, 'kwargs': None,
14171549
'body': [{'ty': 'Pass'}], 'decorator_list': [self.ast_x]}],
14181550
"@x·class x:· pass",
14191551
"^ 0.at_locs.0"
14201552
" ^ 0.decorator_list.0.loc"
1421-
"~~~~~~~~~~~~~~~~~~ 0.loc")
1553+
"~~~~~~~~~~~~~~~~~~ 0.loc",
1554+
validate_if=lambda: sys.version_info >= (3, 0))
14221555

14231556
self.assertParsesSuite(
14241557
[{'ty': 'ClassDef', 'name': 'x', 'bases': [],
1558+
'keywords': [], 'starargs': None, 'kwargs': None,
14251559
'body': [{'ty': 'Pass'}], 'decorator_list': [
14261560
{'ty': 'Call', 'func': self.ast_x,
14271561
'args': [], 'keywords': [], 'kwargs': None, 'starargs': None}
14281562
]}],
14291563
"@x()·class x:· pass",
14301564
"^ 0.at_locs.0"
14311565
" ~~~ 0.decorator_list.0.loc"
1432-
"~~~~~~~~~~~~~~~~~~~~ 0.loc")
1566+
"~~~~~~~~~~~~~~~~~~~~ 0.loc",
1567+
validate_if=lambda: sys.version_info >= (3, 0))
14331568

14341569
self.assertParsesSuite(
14351570
[{'ty': 'ClassDef', 'name': 'x', 'bases': [],
1571+
'keywords': [], 'starargs': None, 'kwargs': None,
14361572
'body': [{'ty': 'Pass'}], 'decorator_list': [
14371573
{'ty': 'Call', 'func': self.ast_x,
14381574
'args': [self.ast_1], 'keywords': [], 'kwargs': None, 'starargs': None}
14391575
]}],
14401576
"@x(1)·class x:· pass",
14411577
"^ 0.at_locs.0"
14421578
" ~~~~ 0.decorator_list.0.loc"
1443-
"~~~~~~~~~~~~~~~~~~~~~ 0.loc")
1579+
"~~~~~~~~~~~~~~~~~~~~~ 0.loc",
1580+
validate_if=lambda: sys.version_info >= (3, 0))
14441581

14451582
self.assertParsesSuite(
14461583
[{'ty': 'FunctionDef', 'name': 'x',
14471584
'args': {'ty': 'arguments', 'args': [], 'defaults': [],
1585+
'kwonlyargs': [], 'kw_defaults': [],
14481586
'kwarg': None, 'vararg': None},
1587+
'returns': None,
14491588
'body': [{'ty': 'Pass'}], 'decorator_list': [self.ast_x]}],
14501589
"@x·def x():· pass",
14511590
"^ 0.at_locs.0"
14521591
" ^ 0.decorator_list.0.loc"
1453-
"~~~~~~~~~~~~~~~~~~ 0.loc")
1592+
"~~~~~~~~~~~~~~~~~~ 0.loc",
1593+
validate_if=lambda: sys.version_info >= (3, 0))
14541594

14551595
#
14561596
# FUNCTION AND LAMBDA ARGUMENTS
@@ -1459,101 +1599,158 @@ def test_decorated(self):
14591599
def test_args(self):
14601600
self.assertParsesArgs(
14611601
{'ty': 'arguments', 'args': [], 'defaults': [],
1602+
'kwonlyargs': [], 'kw_defaults': [],
14621603
'vararg': None, 'kwarg': None},
1463-
"")
1604+
"",
1605+
validate_if=lambda: sys.version_info >= (3, 2))
14641606

14651607
self.assertParsesArgs(
1466-
{'ty': 'arguments', 'args': [self.ast_x], 'defaults': [],
1608+
{'ty': 'arguments', 'args': [self.ast_arg_x], 'defaults': [],
1609+
'kwonlyargs': [], 'kw_defaults': [],
14671610
'vararg': None, 'kwarg': None},
14681611
"x",
14691612
"~ args.0.loc"
1470-
"~ loc")
1613+
"~ loc",
1614+
validate_if=lambda: sys.version_info >= (3, 2))
14711615

14721616
self.assertParsesArgs(
1473-
{'ty': 'arguments', 'args': [self.ast_x], 'defaults': [self.ast_1],
1617+
{'ty': 'arguments', 'args': [self.ast_arg_x], 'defaults': [self.ast_1],
1618+
'kwonlyargs': [], 'kw_defaults': [],
14741619
'vararg': None, 'kwarg': None},
14751620
"x=1",
14761621
"~ args.0.loc"
14771622
" ~ equals_locs.0"
14781623
" ~ defaults.0.loc"
1479-
"~~~ loc")
1624+
"~~~ loc",
1625+
validate_if=lambda: sys.version_info >= (3, 2))
14801626

14811627
self.assertParsesArgs(
1482-
{'ty': 'arguments', 'args': [self.ast_x, self.ast_y], 'defaults': [],
1628+
{'ty': 'arguments', 'args': [self.ast_arg_x, self.ast_arg_y], 'defaults': [],
1629+
'kwonlyargs': [], 'kw_defaults': [],
14831630
'vararg': None, 'kwarg': None},
14841631
"x, y",
1485-
"~~~~ loc")
1632+
"~~~~ loc",
1633+
validate_if=lambda: sys.version_info >= (3, 2))
14861634

14871635
self.assertParsesArgs(
14881636
{'ty': 'arguments', 'args': [], 'defaults': [],
1489-
'vararg': 'y', 'kwarg': None},
1637+
'kwonlyargs': [], 'kw_defaults': [],
1638+
'vararg': self.ast_arg_y, 'kwarg': None},
14901639
"*y",
14911640
"^ star_loc"
1492-
" ~ vararg_loc"
1493-
"~~ loc")
1641+
" ~ vararg.arg_loc"
1642+
" ~ vararg.loc"
1643+
"~~ loc",
1644+
validate_if=lambda: sys.version_info >= (3, 2))
1645+
1646+
self.assertParsesArgs(
1647+
{'ty': 'arguments', 'args': [], 'defaults': [],
1648+
'kwonlyargs': [self.ast_arg_z], 'kw_defaults': [],
1649+
'vararg': self.ast_arg_y, 'kwarg': None},
1650+
"*y, z",
1651+
"~~~~~ loc",
1652+
only_if=lambda ver: ver >= (3, 0),
1653+
validate_if=lambda: sys.version_info >= (3, 2))
1654+
1655+
self.assertParsesArgs(
1656+
{'ty': 'arguments', 'args': [], 'defaults': [],
1657+
'kwonlyargs': [self.ast_arg_z, self.ast_arg_t], 'kw_defaults': [self.ast_1],
1658+
'vararg': self.ast_arg_y, 'kwarg': None},
1659+
"*y, z, t=1",
1660+
"~~~~~~~~~~ loc",
1661+
only_if=lambda ver: ver >= (3, 0),
1662+
validate_if=lambda: sys.version_info >= (3, 2))
14941663

14951664
self.assertParsesArgs(
1496-
{'ty': 'arguments', 'args': [self.ast_x], 'defaults': [],
1497-
'vararg': 'y', 'kwarg': None},
1665+
{'ty': 'arguments', 'args': [self.ast_arg_x], 'defaults': [],
1666+
'kwonlyargs': [], 'kw_defaults': [],
1667+
'vararg': self.ast_arg_y, 'kwarg': None},
14981668
"x, *y",
14991669
" ^ star_loc"
1500-
" ~ vararg_loc"
1501-
"~~~~~ loc")
1670+
"~~~~~ loc",
1671+
validate_if=lambda: sys.version_info >= (3, 2))
15021672

15031673
self.assertParsesArgs(
15041674
{'ty': 'arguments', 'args': [], 'defaults': [],
1505-
'vararg': None, 'kwarg': 'y'},
1675+
'kwonlyargs': [], 'kw_defaults': [],
1676+
'vararg': None, 'kwarg': self.ast_arg_y},
15061677
"**y",
15071678
"^^ dstar_loc"
1508-
" ~ kwarg_loc"
1509-
"~~~ loc")
1679+
"~~~ loc",
1680+
validate_if=lambda: sys.version_info >= (3, 2))
15101681

15111682
self.assertParsesArgs(
1512-
{'ty': 'arguments', 'args': [self.ast_x], 'defaults': [],
1513-
'vararg': None, 'kwarg': 'y'},
1683+
{'ty': 'arguments', 'args': [self.ast_arg_x], 'defaults': [],
1684+
'kwonlyargs': [], 'kw_defaults': [],
1685+
'vararg': None, 'kwarg': self.ast_arg_y},
15141686
"x, **y",
15151687
" ^^ dstar_loc"
1516-
" ~ kwarg_loc"
1517-
"~~~~~~ loc")
1688+
"~~~~~~ loc",
1689+
validate_if=lambda: sys.version_info >= (3, 2))
15181690

15191691
self.assertParsesArgs(
1520-
{'ty': 'arguments', 'args': [self.ast_x], 'defaults': [],
1521-
'vararg': 'y', 'kwarg': 'z'},
1692+
{'ty': 'arguments', 'args': [self.ast_arg_x], 'defaults': [],
1693+
'kwonlyargs': [], 'kw_defaults': [],
1694+
'vararg': self.ast_arg_y, 'kwarg': self.ast_arg_z},
15221695
"x, *y, **z",
15231696
" ^ star_loc"
1524-
" ~ vararg_loc"
15251697
" ^^ dstar_loc"
1526-
" ~ kwarg_loc"
1527-
"~~~~~~~~~~ loc")
1698+
"~~~~~~~~~~ loc",
1699+
validate_if=lambda: sys.version_info >= (3, 2))
15281700

15291701
self.assertParsesArgs(
15301702
{'ty': 'arguments', 'defaults': [], 'vararg': None, 'kwarg': None,
1531-
'args': [{'ty': 'Tuple', 'ctx': None, 'elts': [self.ast_x, self.ast_y]}]},
1703+
'kwonlyargs': [], 'kw_defaults': [],
1704+
'args': [{'ty': 'Tuple', 'ctx': None, 'elts': [self.ast_arg_x, self.ast_arg_y]}]},
15321705
"(x,y)",
15331706
"^ args.0.begin_loc"
15341707
" ^ args.0.end_loc"
15351708
"~~~~~ args.0.loc"
1536-
"~~~~~ loc")
1709+
"~~~~~ loc",
1710+
only_if=lambda ver: ver < (3, 0),
1711+
validate_if=lambda: False)
15371712

15381713
def test_args_def(self):
15391714
self.assertParsesSuite(
15401715
[{'ty': 'FunctionDef', 'name': 'foo',
1541-
'args': {'ty': 'arguments', 'args': [self.ast_x], 'defaults': [],
1716+
'args': {'ty': 'arguments', 'args': [self.ast_arg_x], 'defaults': [],
1717+
'kwonlyargs': [], 'kw_defaults': [],
1718+
'kwarg': None, 'vararg': None},
1719+
'returns': None,
1720+
'body': [{'ty': 'Pass'}], 'decorator_list': []}],
1721+
"def foo(x):· pass",
1722+
validate_if=lambda: sys.version_info >= (3, 0))
1723+
1724+
def test_def_typed(self):
1725+
self.assertParsesSuite(
1726+
[{'ty': 'FunctionDef', 'name': 'foo',
1727+
'args': {'ty': 'arguments',
1728+
'args': [{'ty': 'arg', 'arg': 'x', 'annotation': self.ast_y}],
1729+
'defaults': [],
1730+
'kwonlyargs': [], 'kw_defaults': [],
15421731
'kwarg': None, 'vararg': None},
1732+
'returns': self.ast_z,
15431733
'body': [{'ty': 'Pass'}], 'decorator_list': []}],
1544-
"def foo(x):· pass")
1734+
"def foo(x: y) -> z:· pass",
1735+
" ^ 0.args.args.0.colon_loc"
1736+
" ~~~~ 0.args.args.0.loc"
1737+
" ^^ 0.arrow_loc",
1738+
only_if=lambda ver: ver >= (3, 0),
1739+
validate_if=lambda: sys.version_info >= (3, 0))
15451740

15461741
def test_args_oldlambda(self):
15471742
self.assertParsesExpr(
15481743
{'ty': 'ListComp', 'elt': self.ast_x, 'generators': [
15491744
{'ty': 'comprehension', 'iter': self.ast_z, 'target': self.ast_y,
15501745
'ifs': [{'ty': 'Lambda',
1551-
'args': {'ty': 'arguments', 'args': [self.ast_x], 'defaults': [],
1746+
'args': {'ty': 'arguments', 'args': [self.ast_arg_x], 'defaults': [],
1747+
'kwonlyargs': [], 'kw_defaults': [],
15521748
'kwarg': None, 'vararg': None},
15531749
'body': self.ast_t}
15541750
]}
15551751
]},
1556-
"[x for y in z if lambda x: t]")
1752+
"[x for y in z if lambda x: t]",
1753+
validate_if=lambda: sys.version_info >= (3, 2))
15571754

15581755
#
15591756
# PARSING MODES
@@ -1657,7 +1854,9 @@ def test_diag_call(self):
16571854
"x(*y, z)",
16581855
'fatal', "only named arguments may follow *expression", {},
16591856
" ^ 0"
1660-
" ~~ 1")
1857+
" ~~ 1",
1858+
# see test_call
1859+
only_if=lambda ver: ver not in ((3, 0), (3, 1)))
16611860

16621861
self.assertDiagnoses(
16631862
"x(y=1, z)",

0 commit comments

Comments
 (0)
Please sign in to comment.