https://github.com/python/cpython/commit/3dab11f888fda34c02734e4468d1acd4c36927fe
commit: 3dab11f888fda34c02734e4468d1acd4c36927fe
branch: main
author: Brian Schubert <[email protected]>
committer: pablogsal <[email protected]>
date: 2025-10-26T22:35:21Z
summary:
gh-138944: Fix `SyntaxError` message for invalid syntax following valid
import-as statement (#138945)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2025-09-15-13-06-11.gh-issue-138944.PeCgLb.rst
M Grammar/python.gram
M Lib/test/test_syntax.py
M Parser/parser.c
diff --git a/Grammar/python.gram b/Grammar/python.gram
index 0824b9c658b51a..7ae00c6f005e7e 100644
--- a/Grammar/python.gram
+++ b/Grammar/python.gram
@@ -1416,11 +1416,11 @@ invalid_import:
| 'import' token=NEWLINE {
RAISE_SYNTAX_ERROR_STARTING_FROM(token, "Expected one or more names
after 'import'") }
invalid_dotted_as_name:
- | dotted_name 'as' !(NAME (',' | ')' | NEWLINE)) a=expression {
+ | dotted_name 'as' !(NAME (',' | ')' | ';' | NEWLINE)) a=expression {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a,
"cannot use %s as import target", _PyPegen_get_expr_name(a)) }
invalid_import_from_as_name:
- | NAME 'as' !(NAME (',' | ')' | NEWLINE)) a=expression {
+ | NAME 'as' !(NAME (',' | ')' | ';' | NEWLINE)) a=expression {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a,
"cannot use %s as import target", _PyPegen_get_expr_name(a)) }
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index 3ae23a6c289d3f..ade8f273a1e088 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -2163,6 +2163,25 @@
Traceback (most recent call last):
SyntaxError: cannot use subscript as import target
+# Check that we don't raise a "cannot use name as import target" error
+# if there is an error in an unrelated statement after ';'
+
+>>> import a as b; None = 1
+Traceback (most recent call last):
+SyntaxError: cannot assign to None
+
+>>> import a, b as c; d = 1; None = 1
+Traceback (most recent call last):
+SyntaxError: cannot assign to None
+
+>>> from a import b as c; None = 1
+Traceback (most recent call last):
+SyntaxError: cannot assign to None
+
+>>> from a import b, c as d; e = 1; None = 1
+Traceback (most recent call last):
+SyntaxError: cannot assign to None
+
# Check that we dont raise the "trailing comma" error if there is more
# input to the left of the valid part that we parsed.
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2025-09-15-13-06-11.gh-issue-138944.PeCgLb.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-15-13-06-11.gh-issue-138944.PeCgLb.rst
new file mode 100644
index 00000000000000..248585e2eba995
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-15-13-06-11.gh-issue-138944.PeCgLb.rst
@@ -0,0 +1,3 @@
+Fix :exc:`SyntaxError` message when invalid syntax appears on the same line
+as a valid ``import ... as ...`` or ``from ... import ... as ...``
+statement. Patch by Brian Schubert.
diff --git a/Parser/parser.c b/Parser/parser.c
index 145e30fffaeb16..53417fb2b72b10 100644
--- a/Parser/parser.c
+++ b/Parser/parser.c
@@ -24042,7 +24042,7 @@ invalid_import_rule(Parser *p)
return _res;
}
-// invalid_dotted_as_name: dotted_name 'as' !(NAME (',' | ')' | NEWLINE))
expression
+// invalid_dotted_as_name: dotted_name 'as' !(NAME (',' | ')' | ';' |
NEWLINE)) expression
static void *
invalid_dotted_as_name_rule(Parser *p)
{
@@ -24055,12 +24055,12 @@ invalid_dotted_as_name_rule(Parser *p)
}
void * _res = NULL;
int _mark = p->mark;
- { // dotted_name 'as' !(NAME (',' | ')' | NEWLINE)) expression
+ { // dotted_name 'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> invalid_dotted_as_name[%d-%d]: %s\n",
p->level, ' ', _mark, p->mark, "dotted_name 'as' !(NAME (',' | ')' | NEWLINE))
expression"));
+ D(fprintf(stderr, "%*c> invalid_dotted_as_name[%d-%d]: %s\n",
p->level, ' ', _mark, p->mark, "dotted_name 'as' !(NAME (',' | ')' | ';' |
NEWLINE)) expression"));
Token * _keyword;
expr_ty a;
expr_ty dotted_name_var;
@@ -24074,7 +24074,7 @@ invalid_dotted_as_name_rule(Parser *p)
(a = expression_rule(p)) // expression
)
{
- D(fprintf(stderr, "%*c+ invalid_dotted_as_name[%d-%d]: %s
succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name 'as' !(NAME (',' |
')' | NEWLINE)) expression"));
+ D(fprintf(stderr, "%*c+ invalid_dotted_as_name[%d-%d]: %s
succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name 'as' !(NAME (',' |
')' | ';' | NEWLINE)) expression"));
_res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "cannot use %s as
import target" , _PyPegen_get_expr_name ( a ) );
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -24085,7 +24085,7 @@ invalid_dotted_as_name_rule(Parser *p)
}
p->mark = _mark;
D(fprintf(stderr, "%*c%s invalid_dotted_as_name[%d-%d]: %s failed!\n",
p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark,
"dotted_name 'as' !(NAME (',' | ')' | NEWLINE)) expression"));
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark,
"dotted_name 'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression"));
}
_res = NULL;
done:
@@ -24093,7 +24093,7 @@ invalid_dotted_as_name_rule(Parser *p)
return _res;
}
-// invalid_import_from_as_name: NAME 'as' !(NAME (',' | ')' | NEWLINE))
expression
+// invalid_import_from_as_name: NAME 'as' !(NAME (',' | ')' | ';' | NEWLINE))
expression
static void *
invalid_import_from_as_name_rule(Parser *p)
{
@@ -24106,12 +24106,12 @@ invalid_import_from_as_name_rule(Parser *p)
}
void * _res = NULL;
int _mark = p->mark;
- { // NAME 'as' !(NAME (',' | ')' | NEWLINE)) expression
+ { // NAME 'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> invalid_import_from_as_name[%d-%d]: %s\n",
p->level, ' ', _mark, p->mark, "NAME 'as' !(NAME (',' | ')' | NEWLINE))
expression"));
+ D(fprintf(stderr, "%*c> invalid_import_from_as_name[%d-%d]: %s\n",
p->level, ' ', _mark, p->mark, "NAME 'as' !(NAME (',' | ')' | ';' | NEWLINE))
expression"));
Token * _keyword;
expr_ty a;
expr_ty name_var;
@@ -24125,7 +24125,7 @@ invalid_import_from_as_name_rule(Parser *p)
(a = expression_rule(p)) // expression
)
{
- D(fprintf(stderr, "%*c+ invalid_import_from_as_name[%d-%d]: %s
succeeded!\n", p->level, ' ', _mark, p->mark, "NAME 'as' !(NAME (',' | ')' |
NEWLINE)) expression"));
+ D(fprintf(stderr, "%*c+ invalid_import_from_as_name[%d-%d]: %s
succeeded!\n", p->level, ' ', _mark, p->mark, "NAME 'as' !(NAME (',' | ')' |
';' | NEWLINE)) expression"));
_res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "cannot use %s as
import target" , _PyPegen_get_expr_name ( a ) );
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -24136,7 +24136,7 @@ invalid_import_from_as_name_rule(Parser *p)
}
p->mark = _mark;
D(fprintf(stderr, "%*c%s invalid_import_from_as_name[%d-%d]: %s
failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME
'as' !(NAME (',' | ')' | NEWLINE)) expression"));
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME
'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression"));
}
_res = NULL;
done:
@@ -36240,7 +36240,7 @@ _gather_137_rule(Parser *p)
return _res;
}
-// _tmp_138: NAME (',' | ')' | NEWLINE)
+// _tmp_138: NAME (',' | ')' | ';' | NEWLINE)
static void *
_tmp_138_rule(Parser *p)
{
@@ -36253,27 +36253,27 @@ _tmp_138_rule(Parser *p)
}
void * _res = NULL;
int _mark = p->mark;
- { // NAME (',' | ')' | NEWLINE)
+ { // NAME (',' | ')' | ';' | NEWLINE)
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark,
p->mark, "NAME (',' | ')' | NEWLINE)"));
+ D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark,
p->mark, "NAME (',' | ')' | ';' | NEWLINE)"));
void *_tmp_173_var;
expr_ty name_var;
if (
(name_var = _PyPegen_name_token(p)) // NAME
&&
- (_tmp_173_var = _tmp_173_rule(p)) // ',' | ')' | NEWLINE
+ (_tmp_173_var = _tmp_173_rule(p)) // ',' | ')' | ';' | NEWLINE
)
{
- D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n",
p->level, ' ', _mark, p->mark, "NAME (',' | ')' | NEWLINE)"));
+ D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n",
p->level, ' ', _mark, p->mark, "NAME (',' | ')' | ';' | NEWLINE)"));
_res = _PyPegen_dummy_name(p, name_var, _tmp_173_var);
goto done;
}
p->mark = _mark;
D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME
(',' | ')' | NEWLINE)"));
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME
(',' | ')' | ';' | NEWLINE)"));
}
_res = NULL;
done:
@@ -38235,7 +38235,7 @@ _loop0_172_rule(Parser *p)
return _seq;
}
-// _tmp_173: ',' | ')' | NEWLINE
+// _tmp_173: ',' | ')' | ';' | NEWLINE
static void *
_tmp_173_rule(Parser *p)
{
@@ -38286,6 +38286,25 @@ _tmp_173_rule(Parser *p)
D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'"));
}
+ { // ';'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark,
p->mark, "';'"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 13)) // token=';'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n",
p->level, ' ', _mark, p->mark, "';'"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "';'"));
+ }
{ // NEWLINE
if (p->error_indicator) {
p->level--;
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]