[Python-checkins] [3.10] Backport bpo-47212 (GH-32302) to Python 3.10 (GH-32334)

miss-islington webhook-mailer at python.org
Tue Apr 5 12:21:59 EDT 2022


https://github.com/python/cpython/commit/94609e3192f15636c760a48c4c1c2c236fac3217
commit: 94609e3192f15636c760a48c4c1c2c236fac3217
branch: 3.10
author: Matthieu Dartiailh <marul at laposte.net>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2022-04-05T09:21:49-07:00
summary:

[3.10] Backport bpo-47212 (GH-32302) to Python 3.10 (GH-32334)



(cherry picked from commit aa0f056a00c4bcaef83d729e042359ddae903382)

# Conflicts:
#	Grammar/python.gram
#	Parser/action_helpers.c

Automerge-Triggered-By: GH:pablogsal

files:
A Misc/NEWS.d/next/Core and Builtins/2022-04-05-11-29-21.bpo-47212.leF4pz.rst
M Grammar/python.gram
M Lib/test/test_exceptions.py
M Lib/test/test_syntax.py
M Parser/parser.c
M Parser/pegen.c
M Parser/pegen.h

diff --git a/Grammar/python.gram b/Grammar/python.gram
index 99e01355a582c..84b9c9b82720b 100644
--- a/Grammar/python.gram
+++ b/Grammar/python.gram
@@ -830,12 +830,12 @@ t_lookahead: '(' | '[' | '.'
 invalid_arguments:
     | a=args ',' '*' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "iterable argument unpacking follows keyword argument unpacking") }
     | a=expression b=for_if_clauses ',' [args | expression for_if_clauses] {
-        RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, PyPegen_last_item(b, comprehension_ty)->target, "Generator expression must be parenthesized") }
+        RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, _PyPegen_get_last_comprehension_item(PyPegen_last_item(b, comprehension_ty)), "Generator expression must be parenthesized") }
     | a=NAME b='=' expression for_if_clauses {
         RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Maybe you meant '==' or ':=' instead of '='?")}
     | a=args b=for_if_clauses { _PyPegen_nonparen_genexp_in_call(p, a, b) }
     | args ',' a=expression b=for_if_clauses {
-        RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, asdl_seq_GET(b, b->size-1)->target, "Generator expression must be parenthesized") }
+        RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, _PyPegen_get_last_comprehension_item(PyPegen_last_item(b, comprehension_ty)), "Generator expression must be parenthesized") }
     | a=args ',' args { _PyPegen_arguments_parsing_error(p, a) }
 invalid_kwarg:
     | a[Token*]=('True'|'False'|'None') b='=' {
@@ -975,7 +975,7 @@ invalid_finally_stmt:
 invalid_except_stmt_indent:
     | a='except' expression ['as' NAME ] ':' NEWLINE !INDENT {
         RAISE_INDENTATION_ERROR("expected an indented block after 'except' statement on line %d", a->lineno) }
-    | a='except' ':' NEWLINE !INDENT { RAISE_SYNTAX_ERROR("expected an indented block after except statement on line %d", a->lineno) }
+    | a='except' ':' NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block after 'except' statement on line %d", a->lineno) }
 invalid_match_stmt:
     | "match" subject_expr !':' { CHECK_VERSION(void*, 10, "Pattern matching is", RAISE_SYNTAX_ERROR("expected ':'") ) }
     | a="match" subject=subject_expr ':' NEWLINE !INDENT {
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 2bdd7214b0505..d9ea8a4872d71 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -198,12 +198,17 @@ def ckmsg(src, msg, exception=SyntaxError):
         s = '''if True:\n        print()\n\texec "mixed tabs and spaces"'''
         ckmsg(s, "inconsistent use of tabs and spaces in indentation", TabError)
 
-    def check(self, src, lineno, offset, encoding='utf-8'):
+    def check(self, src, lineno, offset, end_lineno=None, end_offset=None, encoding='utf-8'):
         with self.subTest(source=src, lineno=lineno, offset=offset):
             with self.assertRaises(SyntaxError) as cm:
                 compile(src, '<fragment>', 'exec')
             self.assertEqual(cm.exception.lineno, lineno)
             self.assertEqual(cm.exception.offset, offset)
+            if end_lineno is not None:
+                self.assertEqual(cm.exception.end_lineno, end_lineno)
+            if end_offset is not None:
+                self.assertEqual(cm.exception.end_offset, end_offset)
+
             if cm.exception.text is not None:
                 if not isinstance(src, str):
                     src = src.decode(encoding, 'replace')
@@ -235,6 +240,10 @@ def testSyntaxErrorOffset(self):
         check('match ...:\n    case {**rest, "key": value}:\n        ...', 2, 19)
         check("[a b c d e f]", 1, 2)
         check("for x yfff:", 1, 7)
+        check("f(a for a in b, c)", 1, 3, 1, 15)
+        check("f(a for a in b if a, c)", 1, 3, 1, 20)
+        check("f(a, b for b in c)", 1, 6, 1, 18)
+        check("f(a, b for b in c, d)", 1, 6, 1, 18)
 
         # Errors thrown by compile.c
         check('class foo:return 1', 1, 11)
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index 09c0d5682a7e4..006374e7cd912 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -1012,6 +1012,13 @@
    Traceback (most recent call last):
    IndentationError: expected an indented block after 'try' statement on line 1
 
+   >>> try:
+   ...     something()
+   ... except:
+   ... pass
+   Traceback (most recent call last):
+   IndentationError: expected an indented block after 'except' statement on line 3
+
    >>> try:
    ...     something()
    ... except A:
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-04-05-11-29-21.bpo-47212.leF4pz.rst b/Misc/NEWS.d/next/Core and Builtins/2022-04-05-11-29-21.bpo-47212.leF4pz.rst
new file mode 100644
index 0000000000000..8f1f6b6cfbbb8
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-04-05-11-29-21.bpo-47212.leF4pz.rst	
@@ -0,0 +1,3 @@
+Raise :exc:`IndentationError` instead of :exc:`SyntaxError` for a bare
+``except`` with no following indent. Improve :exc:`SyntaxError` locations for
+an un-parenthesized generator used as arguments. Patch by Matthieu Dartiailh.
diff --git a/Parser/parser.c b/Parser/parser.c
index 3f73003b78973..862950018a312 100644
--- a/Parser/parser.c
+++ b/Parser/parser.c
@@ -18419,7 +18419,7 @@ invalid_arguments_rule(Parser *p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]"));
-            _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , PyPegen_last_item ( b , comprehension_ty ) -> target , "Generator expression must be parenthesized" );
+            _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , _PyPegen_get_last_comprehension_item ( PyPegen_last_item ( b , comprehension_ty ) ) , "Generator expression must be parenthesized" );
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
                 p->level--;
@@ -18512,7 +18512,7 @@ invalid_arguments_rule(Parser *p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ',' expression for_if_clauses"));
-            _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , asdl_seq_GET ( b , b -> size - 1 ) -> target , "Generator expression must be parenthesized" );
+            _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , _PyPegen_get_last_comprehension_item ( PyPegen_last_item ( b , comprehension_ty ) ) , "Generator expression must be parenthesized" );
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
                 p->level--;
@@ -20804,7 +20804,7 @@ invalid_except_stmt_indent_rule(Parser *p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_except_stmt_indent[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except' ':' NEWLINE !INDENT"));
-            _res = RAISE_SYNTAX_ERROR ( "expected an indented block after except statement on line %d" , a -> lineno );
+            _res = RAISE_INDENTATION_ERROR ( "expected an indented block after 'except' statement on line %d" , a -> lineno );
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
                 p->level--;
diff --git a/Parser/pegen.c b/Parser/pegen.c
index 90a6ab98cf42e..c04824315c7a3 100644
--- a/Parser/pegen.c
+++ b/Parser/pegen.c
@@ -2568,7 +2568,7 @@ void *_PyPegen_arguments_parsing_error(Parser *p, expr_ty e) {
 }
 
 
-static inline expr_ty
+expr_ty
 _PyPegen_get_last_comprehension_item(comprehension_ty comprehension) {
     if (comprehension->ifs == NULL || asdl_seq_LEN(comprehension->ifs) == 0) {
         return comprehension->iter;
diff --git a/Parser/pegen.h b/Parser/pegen.h
index 0e5a057c1f196..118fbc7b3b78a 100644
--- a/Parser/pegen.h
+++ b/Parser/pegen.h
@@ -327,6 +327,7 @@ _RAISE_SYNTAX_ERROR_INVALID_TARGET(Parser *p, TARGETS_TYPE type, void *e)
 }
 
 void *_PyPegen_arguments_parsing_error(Parser *, expr_ty);
+expr_ty _PyPegen_get_last_comprehension_item(comprehension_ty comprehension);
 void *_PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args, asdl_comprehension_seq *comprehensions);
 
 



More information about the Python-checkins mailing list