Index: Python/graminit.c =================================================================== --- Python/graminit.c (revision 83046) +++ Python/graminit.c (working copy) @@ -189,11 +189,13 @@ {30, 7}, {0, 6}, }; -static arc arcs_8_7[2] = { +static arc arcs_8_7[3] = { {28, 12}, {32, 3}, + {0, 7}, }; -static arc arcs_8_8[1] = { +static arc arcs_8_8[2] = { + {30, 13}, {0, 8}, }; static arc arcs_8_9[2] = { @@ -206,35 +208,39 @@ {0, 10}, }; static arc arcs_8_11[3] = { - {28, 13}, - {30, 14}, + {28, 14}, + {30, 15}, {0, 11}, }; static arc arcs_8_12[3] = { {30, 7}, - {29, 15}, + {29, 16}, {0, 12}, }; -static arc arcs_8_13[2] = { - {30, 14}, +static arc arcs_8_13[1] = { {0, 13}, }; static arc arcs_8_14[2] = { - {28, 16}, + {30, 15}, + {0, 14}, +}; +static arc arcs_8_15[3] = { + {28, 17}, {32, 3}, + {0, 15}, }; -static arc arcs_8_15[1] = { +static arc arcs_8_16[1] = { {24, 6}, }; -static arc arcs_8_16[3] = { - {30, 14}, - {29, 17}, - {0, 16}, +static arc arcs_8_17[3] = { + {30, 15}, + {29, 18}, + {0, 17}, }; -static arc arcs_8_17[1] = { - {24, 13}, +static arc arcs_8_18[1] = { + {24, 14}, }; -static state states_8[18] = { +static state states_8[19] = { {3, arcs_8_0}, {3, arcs_8_1}, {3, arcs_8_2}, @@ -242,17 +248,18 @@ {1, arcs_8_4}, {4, arcs_8_5}, {2, arcs_8_6}, - {2, arcs_8_7}, - {1, arcs_8_8}, + {3, arcs_8_7}, + {2, arcs_8_8}, {2, arcs_8_9}, {3, arcs_8_10}, {3, arcs_8_11}, {3, arcs_8_12}, - {2, arcs_8_13}, + {1, arcs_8_13}, {2, arcs_8_14}, - {1, arcs_8_15}, - {3, arcs_8_16}, - {1, arcs_8_17}, + {3, arcs_8_15}, + {1, arcs_8_16}, + {3, arcs_8_17}, + {1, arcs_8_18}, }; static arc arcs_9_0[1] = { {21, 1}, @@ -304,11 +311,13 @@ {30, 7}, {0, 6}, }; -static arc arcs_10_7[2] = { +static arc arcs_10_7[3] = { {34, 12}, {32, 3}, + {0, 7}, }; -static arc arcs_10_8[1] = { +static arc arcs_10_8[2] = { + {30, 13}, {0, 8}, }; static arc arcs_10_9[2] = { @@ -321,35 +330,39 @@ {0, 10}, }; static arc arcs_10_11[3] = { - {34, 13}, - {30, 14}, + {34, 14}, + {30, 15}, {0, 11}, }; static arc arcs_10_12[3] = { {30, 7}, - {29, 15}, + {29, 16}, {0, 12}, }; -static arc arcs_10_13[2] = { - {30, 14}, +static arc arcs_10_13[1] = { {0, 13}, }; static arc arcs_10_14[2] = { - {34, 16}, + {30, 15}, + {0, 14}, +}; +static arc arcs_10_15[3] = { + {34, 17}, {32, 3}, + {0, 15}, }; -static arc arcs_10_15[1] = { +static arc arcs_10_16[1] = { {24, 6}, }; -static arc arcs_10_16[3] = { - {30, 14}, - {29, 17}, - {0, 16}, +static arc arcs_10_17[3] = { + {30, 15}, + {29, 18}, + {0, 17}, }; -static arc arcs_10_17[1] = { - {24, 13}, +static arc arcs_10_18[1] = { + {24, 14}, }; -static state states_10[18] = { +static state states_10[19] = { {3, arcs_10_0}, {3, arcs_10_1}, {3, arcs_10_2}, @@ -357,17 +370,18 @@ {1, arcs_10_4}, {4, arcs_10_5}, {2, arcs_10_6}, - {2, arcs_10_7}, - {1, arcs_10_8}, + {3, arcs_10_7}, + {2, arcs_10_8}, {2, arcs_10_9}, {3, arcs_10_10}, {3, arcs_10_11}, {3, arcs_10_12}, - {2, arcs_10_13}, + {1, arcs_10_13}, {2, arcs_10_14}, - {1, arcs_10_15}, - {3, arcs_10_16}, - {1, arcs_10_17}, + {3, arcs_10_15}, + {1, arcs_10_16}, + {3, arcs_10_17}, + {1, arcs_10_18}, }; static arc arcs_11_0[1] = { {21, 1}, @@ -1819,11 +1833,11 @@ "\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {263, "parameters", 0, 4, states_7, "\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {264, "typedargslist", 0, 18, states_8, + {264, "typedargslist", 0, 19, states_8, "\000\000\040\200\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {265, "tfpdef", 0, 4, states_9, "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {266, "varargslist", 0, 18, states_10, + {266, "varargslist", 0, 19, states_10, "\000\000\040\200\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {267, "vfpdef", 0, 2, states_11, "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, Index: Python/ast.c =================================================================== --- Python/ast.c (revision 83046) +++ Python/ast.c (working copy) @@ -738,16 +738,20 @@ and varargslist (lambda definition). parameters: '(' [typedargslist] ')' - typedargslist: ((tfpdef ['=' test] ',')* - ('*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] - | '**' tfpdef) - | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) + typedargslist: (tfpdef ['=' test] (',' tfpdef ['=' test])* [',' [ + '*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]] + | '**' tfpdef [',']]] + | '*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]] + | '**' tfpdef [',']) tfpdef: NAME [':' test] - varargslist: ((vfpdef ['=' test] ',')* - ('*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] - | '**' vfpdef) - | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) + varargslist: (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [ + '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]] + | '**' vfpdef [',']]] + | '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]] + | '**' vfpdef [','] + ) vfpdef: NAME + */ int i, j, k, nposargs = 0, nkwonlyargs = 0; int nposdefaults = 0, found_default = 0; @@ -851,7 +855,8 @@ i += 2; /* the name and the comma */ break; case STAR: - if (i+1 >= NCH(n)) { + if (i+1 >= NCH(n) || + (i+2 == NCH(n) && TYPE(CHILD(n, i+1)) == COMMA)) { ast_error(CHILD(n, i), "named arguments must follow bare *"); goto error; Index: Grammar/Grammar =================================================================== --- Grammar/Grammar (revision 83046) +++ Grammar/Grammar (working copy) @@ -24,13 +24,18 @@ decorated: decorators (classdef | funcdef) funcdef: 'def' NAME parameters ['->' test] ':' suite parameters: '(' [typedargslist] ')' -typedargslist: (tfpdef ['=' test] (',' tfpdef ['=' test])* [',' - ['*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef]] - | '*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef) +typedargslist: (tfpdef ['=' test] (',' tfpdef ['=' test])* [',' [ + '*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]] + | '**' tfpdef [',']]] + | '*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]] + | '**' tfpdef [',']) tfpdef: NAME [':' test] -varargslist: (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' - ['*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef]] - | '*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef) +varargslist: (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [ + '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]] + | '**' vfpdef [',']]] + | '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]] + | '**' vfpdef [','] +) vfpdef: NAME stmt: simple_stmt | compound_stmt Index: Misc/NEWS =================================================================== --- Misc/NEWS (revision 83046) +++ Misc/NEWS (working copy) @@ -12,6 +12,9 @@ Core and Builtins ----------------- +- Issue #9232: Modify Python's grammar to allow trailing commas in the + argument list of a function declaration. (Example: f(*, a=3,).) + - Issue #7616: Fix copying of overlapping memoryview slices with the Intel compiler. Index: Doc/reference/compound_stmts.rst =================================================================== --- Doc/reference/compound_stmts.rst (revision 83046) +++ Doc/reference/compound_stmts.rst (working copy) @@ -429,11 +429,10 @@ decorators: `decorator`+ decorator: "@" `dotted_name` ["(" [`argument_list` [","]] ")"] NEWLINE dotted_name: `identifier` ("." `identifier`)* - parameter_list: (`defparameter` ",")* - : ( "*" [`parameter`] ("," `defparameter`)* - : [, "**" `parameter`] - : | "**" `parameter` - : | `defparameter` [","] ) + parameter_list: `defparameter` ("," `defparameter`)* ["," [`parameter_list_starargs`]] + : | `parameter_list_starargs` + parameter_list_starargs: "*" [`parameter`] ("," `defparameter`)* ["," ["**" `parameter` [","]]] + : | "**" `parameter` [","] parameter: `identifier` [":" `expression`] defparameter: `parameter` ["=" `expression`] funcname: `identifier` Index: Lib/test/test_grammar.py =================================================================== --- Lib/test/test_grammar.py (revision 83046) +++ Lib/test/test_grammar.py (working copy) @@ -278,6 +278,10 @@ pos2key2dict(1,2,k2=100,tokwarg1=100,tokwarg2=200) pos2key2dict(1,2,tokwarg1=100,tokwarg2=200, k2=100) + self.assertRaises(SyntaxError, eval, "def f(*): pass") + self.assertRaises(SyntaxError, eval, "def f(*,): pass") + self.assertRaises(SyntaxError, eval, "def f(*, **kwds): pass") + # keyword arguments after *arglist def f(*args, **kwargs): return args, kwargs @@ -324,6 +328,23 @@ check_syntax_error(self, "f(*g(1=2))") check_syntax_error(self, "f(**g(1=2))") + # Check trailing commas are permitted in funcdef argument list + def f(a,): pass + def f(*args,): pass + def f(**kwds,): pass + def f(a, *args,): pass + def f(a, **kwds,): pass + def f(*args, b,): pass + def f(*, b,): pass + def f(*args, **kwds,): pass + def f(a, *args, b,): pass + def f(a, *, b,): pass + def f(a, *args, **kwds,): pass + def f(*args, b, **kwds,): pass + def f(*, b, **kwds,): pass + def f(a, *args, b, **kwds,): pass + def f(a, *, b, **kwds,): pass + def testLambdef(self): ### lambdef: 'lambda' [varargslist] ':' test l1 = lambda : 0 @@ -342,7 +363,24 @@ self.assertEqual(l6(1,2), 1+2+20) self.assertEqual(l6(1,2,k=10), 1+2+10) + # check that trailing commas are permitted + l10 = lambda a,: 0 + l11 = lambda *args,: 0 + l12 = lambda **kwds,: 0 + l13 = lambda a, *args,: 0 + l14 = lambda a, **kwds,: 0 + l15 = lambda *args, b,: 0 + l16 = lambda *, b,: 0 + l17 = lambda *args, **kwds,: 0 + l18 = lambda a, *args, b,: 0 + l19 = lambda a, *, b,: 0 + l20 = lambda a, *args, **kwds,: 0 + l21 = lambda *args, b, **kwds,: 0 + l22 = lambda *, b, **kwds,: 0 + l23 = lambda a, *args, b, **kwds,: 0 + l24 = lambda a, *, b, **kwds,: 0 + ### stmt: simple_stmt | compound_stmt # Tested below