Index: Python/graminit.c =================================================================== --- Python/graminit.c (revision 65325) +++ Python/graminit.c (working copy) @@ -1609,7 +1609,8 @@ static arc arcs_74_6[1] = { {0, 6}, }; -static arc arcs_74_7[1] = { +static arc arcs_74_7[2] = { + {162, 5}, {31, 3}, }; static state states_74[8] = { @@ -1620,7 +1621,7 @@ {4, arcs_74_4}, {2, arcs_74_5}, {1, arcs_74_6}, - {1, arcs_74_7}, + {2, arcs_74_7}, }; static arc arcs_75_0[1] = { {28, 1}, Index: Python/ast.c =================================================================== --- Python/ast.c (revision 65325) +++ Python/ast.c (working copy) @@ -1898,6 +1898,11 @@ "non-keyword arg after keyword arg"); return NULL; } + if (vararg) { + ast_error(CHILD(ch, 0), + "only named arguments may follow *expression"); + return NULL; + } e = ast_for_expr(c, CHILD(ch, 0)); if (!e) return NULL; Index: Grammar/Grammar =================================================================== --- Grammar/Grammar (revision 65325) +++ Grammar/Grammar (working copy) @@ -130,7 +130,9 @@ classdef: 'class' NAME ['(' [testlist] ')'] ':' suite -arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test) +arglist: (argument ',')* (argument [','] + |'*' test (',' argument)* [',' '**' test] + |'**' test) argument: test [gen_for] | test '=' test # Really [keyword '='] test list_iter: list_for | list_if Index: Doc/reference/expressions.rst =================================================================== --- Doc/reference/expressions.rst (revision 65325) +++ Doc/reference/expressions.rst (working copy) @@ -625,11 +625,11 @@ call: `primary` "(" [`argument_list` [","] : | `expression` `genexpr_for`] ")" argument_list: `positional_arguments` ["," `keyword_arguments`] - : ["," "*" `expression`] - : ["," "**" `expression`] + : ["," "*" `expression`] ["," `keyword_arguments`] + : ["," "**" `expression`] : | `keyword_arguments` ["," "*" `expression`] - : ["," "**" `expression`] - : | "*" `expression` ["," "**" `expression`] + : ["," "**" `expression`] + : | "*" `expression` ["," "*" `expression`] ["," "**" `expression`] : | "**" `expression` positional_arguments: `expression` ("," `expression`)* keyword_arguments: `keyword_item` ("," `keyword_item`)* @@ -686,12 +686,13 @@ If the syntax ``*expression`` appears in the function call, ``expression`` must evaluate to a sequence. Elements from this sequence are treated as if they were -additional positional arguments; if there are positional arguments *x1*,...,*xN* -, and ``expression`` evaluates to a sequence *y1*,...,*yM*, this is equivalent -to a call with M+N positional arguments *x1*,...,*xN*,*y1*,...,*yM*. +additional positional arguments; if there are positional arguments *x1*,..., +*xN*, and ``expression`` evaluates to a sequence *y1*, ..., *yM*, this is +equivalent to a call with M+N positional arguments *x1*, ..., *xN*, *y1*, ..., +*yM*. -A consequence of this is that although the ``*expression`` syntax appears -*after* any keyword arguments, it is processed *before* the keyword arguments +A consequence of this is that although the ``*expression`` syntax may appear +*after* some keyword arguments, it is processed *before* the keyword arguments (and the ``**expression`` argument, if any -- see below). So:: >>> def f(a, b): Index: Lib/test/test_grammar.py =================================================================== --- Lib/test/test_grammar.py (revision 65325) +++ Lib/test/test_grammar.py (working copy) @@ -282,6 +282,14 @@ def d32v((x,)): pass d32v((1,)) + # keyword arguments after *arglist + def f(*args, **kwargs): + return args, kwargs + self.assertEquals(f(1, x=2, *[3, 4], y=5), ((1, 3, 4), + {'x':2, 'y':5})) + self.assertRaises(SyntaxError, eval, "f(1, *(2,3), 4)") + self.assertRaises(SyntaxError, eval, "f(1, x=2, *(3,4), x=5)") + # Check ast errors in *args and *kwargs check_syntax_error(self, "f(*g(1=2))") check_syntax_error(self, "f(**g(1=2))")