diff --git a/Grammar/python.gram b/Grammar/python.gram index b107e474630..97114b20f5d 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -1169,7 +1169,7 @@ invalid_group: | '(' a='**' expression ')' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use double starred expression here") } invalid_import_from_targets: - | import_from_as_names ',' { + | import_from_as_names ',' NEWLINE { RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") } invalid_with_stmt: diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index c77aafeb363..88503dcaad9 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -1202,6 +1202,13 @@ Traceback (most recent call last): SyntaxError: trailing comma not allowed without surrounding parentheses +# Check that we dont raise the "trailing comma" error if there is more +# input to the left of the valid part that we parsed. + +>>> from t import x,y, and 3 +Traceback (most recent call last): +SyntaxError: invalid syntax + >>> (): int Traceback (most recent call last): SyntaxError: only single target (not tuple) can be annotated diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-08-18-19-09-28.bpo-44947.mcvGdS.rst b/Misc/NEWS.d/next/Core and Builtins/2021-08-18-19-09-28.bpo-44947.mcvGdS.rst new file mode 100644 index 00000000000..d531ba9faf3 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-08-18-19-09-28.bpo-44947.mcvGdS.rst @@ -0,0 +1,2 @@ +Refine the syntax error for trailing commas in import statements. Patch by +Pablo Galindo. diff --git a/Parser/parser.c b/Parser/parser.c index 01082fa1d77..87227b7f2f7 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -19540,7 +19540,7 @@ invalid_group_rule(Parser *p) return _res; } -// invalid_import_from_targets: import_from_as_names ',' +// invalid_import_from_targets: import_from_as_names ',' NEWLINE static void * invalid_import_from_targets_rule(Parser *p) { @@ -19551,21 +19551,24 @@ invalid_import_from_targets_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // import_from_as_names ',' + { // import_from_as_names ',' NEWLINE if (p->error_indicator) { D(p->level--); return NULL; } - D(fprintf(stderr, "%*c> invalid_import_from_targets[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "import_from_as_names ','")); + D(fprintf(stderr, "%*c> invalid_import_from_targets[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "import_from_as_names ',' NEWLINE")); Token * _literal; asdl_alias_seq* import_from_as_names_var; + Token * newline_var; if ( (import_from_as_names_var = import_from_as_names_rule(p)) // import_from_as_names && (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ invalid_import_from_targets[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "import_from_as_names ','")); + D(fprintf(stderr, "%*c+ invalid_import_from_targets[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "import_from_as_names ',' NEWLINE")); _res = RAISE_SYNTAX_ERROR ( "trailing comma not allowed without surrounding parentheses" ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -19576,7 +19579,7 @@ invalid_import_from_targets_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s invalid_import_from_targets[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "import_from_as_names ','")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "import_from_as_names ',' NEWLINE")); } _res = NULL; done: