Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2832574

Browse files
committed
Issue #25969: Update the lib2to3 grammar to handle the unpacking
generalizations added in 3.5.
1 parent dbdf029 commit 2832574

7 files changed

Lines changed: 91 additions & 6 deletions

File tree

Lib/lib2to3/Grammar.txt

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,26 @@ subscript: test | [test] ':' [test] [sliceop]
138138
sliceop: ':' [test]
139139
exprlist: (expr|star_expr) (',' (expr|star_expr))* [',']
140140
testlist: test (',' test)* [',']
141-
dictsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) |
142-
(test (comp_for | (',' test)* [','])) )
141+
dictsetmaker: ( ((test ':' test | '**' expr)
142+
(comp_for | (',' (test ':' test | '**' expr))* [','])) |
143+
((test | star_expr)
144+
(comp_for | (',' (test | star_expr))* [','])) )
143145

144146
classdef: 'class' NAME ['(' [arglist] ')'] ':' suite
145147

146-
arglist: (argument ',')* (argument [',']
147-
|'*' test (',' argument)* [',' '**' test]
148-
|'**' test)
149-
argument: test [comp_for] | test '=' test # Really [keyword '='] test
148+
arglist: argument (',' argument)* [',']
149+
150+
# "test '=' test" is really "keyword '=' test", but we have no such token.
151+
# These need to be in a single rule to avoid grammar that is ambiguous
152+
# to our LL(1) parser. Even though 'test' includes '*expr' in star_expr,
153+
# we explicitly match '*' here, too, to give it proper precedence.
154+
# Illegal combinations and orderings are blocked in ast.c:
155+
# multiple (test comp_for) arguements are blocked; keyword unpackings
156+
# that precede iterable unpackings are blocked; etc.
157+
argument: ( test [comp_for] |
158+
test '=' test |
159+
'**' expr |
160+
star_expr )
150161

151162
comp_iter: comp_for | comp_if
152163
comp_for: 'for' exprlist 'in' testlist_safe [comp_iter]

Lib/lib2to3/fixes/fix_apply.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ def transform(self, node, results):
3434
func = results["func"]
3535
args = results["args"]
3636
kwds = results.get("kwds")
37+
# I feel like we should be able to express this logic in the
38+
# PATTERN above but I don't know how to do it so...
39+
if args:
40+
if args.type == self.syms.star_expr:
41+
return # Make no change.
42+
if (args.type == self.syms.argument and
43+
args.children[0].value == '**'):
44+
return # Make no change.
45+
if kwds and (kwds.type == self.syms.argument and
46+
kwds.children[0].value == '**'):
47+
return # Make no change.
3748
prefix = node.prefix
3849
func = func.clone()
3950
if (func.type not in (token.NAME, syms.atom) and

Lib/lib2to3/fixes/fix_intern.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ class FixIntern(fixer_base.BaseFix):
2525
"""
2626

2727
def transform(self, node, results):
28+
if results:
29+
# I feel like we should be able to express this logic in the
30+
# PATTERN above but I don't know how to do it so...
31+
obj = results['obj']
32+
if obj:
33+
if obj.type == self.syms.star_expr:
34+
return # Make no change.
35+
if (obj.type == self.syms.argument and
36+
obj.children[0].value == '**'):
37+
return # Make no change.
2838
names = ('sys', 'intern')
2939
new = ImportAndCall(node, results, names)
3040
touch_import(None, 'sys', node)

Lib/lib2to3/fixes/fix_reload.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ class FixReload(fixer_base.BaseFix):
2222
"""
2323

2424
def transform(self, node, results):
25+
if results:
26+
# I feel like we should be able to express this logic in the
27+
# PATTERN above but I don't know how to do it so...
28+
obj = results['obj']
29+
print('obj:', repr(obj))
30+
if obj:
31+
if obj.type == self.syms.star_expr:
32+
return # Make no change.
33+
if (obj.type == self.syms.argument and
34+
obj.children[0].value == '**'):
35+
return # Make no change.
2536
names = ('imp', 'reload')
2637
new = ImportAndCall(node, results, names)
2738
touch_import(None, 'imp', node)

Lib/lib2to3/tests/test_fixers.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,10 @@ def test_unchanged_6(self):
260260
s = """apply(f, *args)"""
261261
self.unchanged(s)
262262

263+
def test_unchanged_6b(self):
264+
s = """apply(f, **kwds)"""
265+
self.unchanged(s)
266+
263267
def test_unchanged_7(self):
264268
s = """apply(func=f, args=args, kwds=kwds)"""
265269
self.unchanged(s)

Lib/lib2to3/tests/test_parser.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,41 @@ def test_3x_style_invalid_4(self):
208208
self.invalid_syntax("raise E from")
209209

210210

211+
# Modelled after Lib/test/test_grammar.py:TokenTests.test_funcdef issue2292
212+
# and Lib/test/text_parser.py test_list_displays, test_set_displays,
213+
# test_dict_displays, test_argument_unpacking, ... changes.
214+
class TestUnpackingGeneralizations(GrammarTest):
215+
def test_mid_positional_star(self):
216+
self.validate("""func(1, *(2, 3), 4)""")
217+
218+
def test_double_star_dict_literal(self):
219+
self.validate("""func(**{'eggs':'scrambled', 'spam':'fried'})""")
220+
221+
def test_double_star_dict_literal_after_keywords(self):
222+
self.validate("""func(spam='fried', **{'eggs':'scrambled'})""")
223+
224+
def test_list_display(self):
225+
self.validate("""[*{2}, 3, *[4]]""")
226+
227+
def test_set_display(self):
228+
self.validate("""{*{2}, 3, *[4]}""")
229+
230+
def test_dict_display_1(self):
231+
self.validate("""{**{}}""")
232+
233+
def test_dict_display_2(self):
234+
self.validate("""{**{}, 3:4, **{5:6, 7:8}}""")
235+
236+
def test_argument_unpacking_1(self):
237+
self.validate("""f(a, *b, *c, d)""")
238+
239+
def test_argument_unpacking_2(self):
240+
self.validate("""f(**a, **b)""")
241+
242+
def test_argument_unpacking_3(self):
243+
self.validate("""f(2, *a, *b, **b, **c, **d)""")
244+
245+
211246
# Adapted from Python 3's Lib/test/test_grammar.py:GrammarTests.testFuncdef
212247
class TestFunctionAnnotations(GrammarTest):
213248
def test_1(self):

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ Core and Builtins
6565
Library
6666
-------
6767

68+
- Issue #25969: Update the lib2to3 grammar to handle the unpacking
69+
generalizations added in 3.5.
70+
6871
- Issue #27932: Fixes memory leak in platform.win32_ver()
6972

7073
- Issue #14977: mailcap now respects the order of the lines in the mailcap

0 commit comments

Comments
 (0)