Skip to content

Commit 94609e3

Browse files
[3.10] Backport bpo-47212 (GH-32302) to Python 3.10 (GH-32334)
(cherry picked from commit aa0f056) # Conflicts: # Grammar/python.gram # Parser/action_helpers.c Automerge-Triggered-By: GH:pablogsal
1 parent 857cf55 commit 94609e3

File tree

7 files changed

+28
-8
lines changed

7 files changed

+28
-8
lines changed

Grammar/python.gram

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -830,12 +830,12 @@ t_lookahead: '(' | '[' | '.'
830830
invalid_arguments:
831831
| a=args ',' '*' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "iterable argument unpacking follows keyword argument unpacking") }
832832
| a=expression b=for_if_clauses ',' [args | expression for_if_clauses] {
833-
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, PyPegen_last_item(b, comprehension_ty)->target, "Generator expression must be parenthesized") }
833+
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, _PyPegen_get_last_comprehension_item(PyPegen_last_item(b, comprehension_ty)), "Generator expression must be parenthesized") }
834834
| a=NAME b='=' expression for_if_clauses {
835835
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Maybe you meant '==' or ':=' instead of '='?")}
836836
| a=args b=for_if_clauses { _PyPegen_nonparen_genexp_in_call(p, a, b) }
837837
| args ',' a=expression b=for_if_clauses {
838-
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, asdl_seq_GET(b, b->size-1)->target, "Generator expression must be parenthesized") }
838+
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, _PyPegen_get_last_comprehension_item(PyPegen_last_item(b, comprehension_ty)), "Generator expression must be parenthesized") }
839839
| a=args ',' args { _PyPegen_arguments_parsing_error(p, a) }
840840
invalid_kwarg:
841841
| a[Token*]=('True'|'False'|'None') b='=' {
@@ -975,7 +975,7 @@ invalid_finally_stmt:
975975
invalid_except_stmt_indent:
976976
| a='except' expression ['as' NAME ] ':' NEWLINE !INDENT {
977977
RAISE_INDENTATION_ERROR("expected an indented block after 'except' statement on line %d", a->lineno) }
978-
| a='except' ':' NEWLINE !INDENT { RAISE_SYNTAX_ERROR("expected an indented block after except statement on line %d", a->lineno) }
978+
| a='except' ':' NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block after 'except' statement on line %d", a->lineno) }
979979
invalid_match_stmt:
980980
| "match" subject_expr !':' { CHECK_VERSION(void*, 10, "Pattern matching is", RAISE_SYNTAX_ERROR("expected ':'") ) }
981981
| a="match" subject=subject_expr ':' NEWLINE !INDENT {

Lib/test/test_exceptions.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,17 @@ def ckmsg(src, msg, exception=SyntaxError):
198198
s = '''if True:\n print()\n\texec "mixed tabs and spaces"'''
199199
ckmsg(s, "inconsistent use of tabs and spaces in indentation", TabError)
200200

201-
def check(self, src, lineno, offset, encoding='utf-8'):
201+
def check(self, src, lineno, offset, end_lineno=None, end_offset=None, encoding='utf-8'):
202202
with self.subTest(source=src, lineno=lineno, offset=offset):
203203
with self.assertRaises(SyntaxError) as cm:
204204
compile(src, '<fragment>', 'exec')
205205
self.assertEqual(cm.exception.lineno, lineno)
206206
self.assertEqual(cm.exception.offset, offset)
207+
if end_lineno is not None:
208+
self.assertEqual(cm.exception.end_lineno, end_lineno)
209+
if end_offset is not None:
210+
self.assertEqual(cm.exception.end_offset, end_offset)
211+
207212
if cm.exception.text is not None:
208213
if not isinstance(src, str):
209214
src = src.decode(encoding, 'replace')
@@ -235,6 +240,10 @@ def testSyntaxErrorOffset(self):
235240
check('match ...:\n case {**rest, "key": value}:\n ...', 2, 19)
236241
check("[a b c d e f]", 1, 2)
237242
check("for x yfff:", 1, 7)
243+
check("f(a for a in b, c)", 1, 3, 1, 15)
244+
check("f(a for a in b if a, c)", 1, 3, 1, 20)
245+
check("f(a, b for b in c)", 1, 6, 1, 18)
246+
check("f(a, b for b in c, d)", 1, 6, 1, 18)
238247

239248
# Errors thrown by compile.c
240249
check('class foo:return 1', 1, 11)

Lib/test/test_syntax.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,13 @@
10121012
Traceback (most recent call last):
10131013
IndentationError: expected an indented block after 'try' statement on line 1
10141014
1015+
>>> try:
1016+
... something()
1017+
... except:
1018+
... pass
1019+
Traceback (most recent call last):
1020+
IndentationError: expected an indented block after 'except' statement on line 3
1021+
10151022
>>> try:
10161023
... something()
10171024
... except A:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Raise :exc:`IndentationError` instead of :exc:`SyntaxError` for a bare
2+
``except`` with no following indent. Improve :exc:`SyntaxError` locations for
3+
an un-parenthesized generator used as arguments. Patch by Matthieu Dartiailh.

Parser/parser.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18419,7 +18419,7 @@ invalid_arguments_rule(Parser *p)
1841918419
)
1842018420
{
1842118421
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]"));
18422-
_res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , PyPegen_last_item ( b , comprehension_ty ) -> target , "Generator expression must be parenthesized" );
18422+
_res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , _PyPegen_get_last_comprehension_item ( PyPegen_last_item ( b , comprehension_ty ) ) , "Generator expression must be parenthesized" );
1842318423
if (_res == NULL && PyErr_Occurred()) {
1842418424
p->error_indicator = 1;
1842518425
p->level--;
@@ -18512,7 +18512,7 @@ invalid_arguments_rule(Parser *p)
1851218512
)
1851318513
{
1851418514
D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ',' expression for_if_clauses"));
18515-
_res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , asdl_seq_GET ( b , b -> size - 1 ) -> target , "Generator expression must be parenthesized" );
18515+
_res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , _PyPegen_get_last_comprehension_item ( PyPegen_last_item ( b , comprehension_ty ) ) , "Generator expression must be parenthesized" );
1851618516
if (_res == NULL && PyErr_Occurred()) {
1851718517
p->error_indicator = 1;
1851818518
p->level--;
@@ -20804,7 +20804,7 @@ invalid_except_stmt_indent_rule(Parser *p)
2080420804
)
2080520805
{
2080620806
D(fprintf(stderr, "%*c+ invalid_except_stmt_indent[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except' ':' NEWLINE !INDENT"));
20807-
_res = RAISE_SYNTAX_ERROR ( "expected an indented block after except statement on line %d" , a -> lineno );
20807+
_res = RAISE_INDENTATION_ERROR ( "expected an indented block after 'except' statement on line %d" , a -> lineno );
2080820808
if (_res == NULL && PyErr_Occurred()) {
2080920809
p->error_indicator = 1;
2081020810
p->level--;

Parser/pegen.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2568,7 +2568,7 @@ void *_PyPegen_arguments_parsing_error(Parser *p, expr_ty e) {
25682568
}
25692569

25702570

2571-
static inline expr_ty
2571+
expr_ty
25722572
_PyPegen_get_last_comprehension_item(comprehension_ty comprehension) {
25732573
if (comprehension->ifs == NULL || asdl_seq_LEN(comprehension->ifs) == 0) {
25742574
return comprehension->iter;

Parser/pegen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ _RAISE_SYNTAX_ERROR_INVALID_TARGET(Parser *p, TARGETS_TYPE type, void *e)
327327
}
328328

329329
void *_PyPegen_arguments_parsing_error(Parser *, expr_ty);
330+
expr_ty _PyPegen_get_last_comprehension_item(comprehension_ty comprehension);
330331
void *_PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args, asdl_comprehension_seq *comprehensions);
331332

332333

0 commit comments

Comments
 (0)