https://github.com/python/cpython/commit/d0c78a458b3b3d908981fe306f77865de35d040a
commit: d0c78a458b3b3d908981fe306f77865de35d040a
branch: 3.14
author: Brian Schubert <[email protected]>
committer: lysnikolaou <[email protected]>
date: 2025-10-31T11:26:40+01:00
summary:

[3.14] gh-138944: Fix `SyntaxError` message for invalid syntax following valid 
import-as statement (GH-138945) (#140646)

(cherry picked from commit 3dab11f888fda34c02734e4468d1acd4c36927fe)

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 27748bf1d91b67..7b27b04bf7989e 100644
--- a/Grammar/python.gram
+++ b/Grammar/python.gram
@@ -1387,11 +1387,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 2624588a41b165..de8c94fe8d2d18 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -2111,6 +2111,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 95521b9933c348..1c507937077deb 100644
--- a/Parser/parser.c
+++ b/Parser/parser.c
@@ -23692,7 +23692,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)
 {
@@ -23705,12 +23705,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;
@@ -23724,7 +23724,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;
@@ -23735,7 +23735,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:
@@ -23743,7 +23743,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)
 {
@@ -23756,12 +23756,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;
@@ -23775,7 +23775,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;
@@ -23786,7 +23786,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:
@@ -35834,7 +35834,7 @@ _gather_138_rule(Parser *p)
     return _res;
 }
 
-// _tmp_139: NAME (',' | ')' | NEWLINE)
+// _tmp_139: NAME (',' | ')' | ';' | NEWLINE)
 static void *
 _tmp_139_rule(Parser *p)
 {
@@ -35847,27 +35847,27 @@ _tmp_139_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_139[%d-%d]: %s\n", p->level, ' ', _mark, 
p->mark, "NAME (',' | ')' | NEWLINE)"));
+        D(fprintf(stderr, "%*c> _tmp_139[%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_139[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "NAME (',' | ')' | NEWLINE)"));
+            D(fprintf(stderr, "%*c+ _tmp_139[%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_139[%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:
@@ -37788,7 +37788,7 @@ _loop0_172_rule(Parser *p)
     return _seq;
 }
 
-// _tmp_173: ',' | ')' | NEWLINE
+// _tmp_173: ',' | ')' | ';' | NEWLINE
 static void *
 _tmp_173_rule(Parser *p)
 {
@@ -37839,6 +37839,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]

Reply via email to