Skip to content

Commit 2e0a920

Browse files
authored
bpo-41084: Adjust message when an f-string expression causes a SyntaxError (GH-21084)
Prefix the error message with `fstring: `, when parsing an f-string expression throws a `SyntaxError`.
1 parent ef19bad commit 2e0a920

File tree

3 files changed

+29
-3
lines changed

3 files changed

+29
-3
lines changed

Lib/test/test_fstring.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ def test_format_specifier_expressions(self):
524524
# This looks like a nested format spec.
525525
])
526526

527-
self.assertAllRaise(SyntaxError, "invalid syntax",
527+
self.assertAllRaise(SyntaxError, "f-string: invalid syntax",
528528
[# Invalid syntax inside a nested spec.
529529
"f'{4:{/5}}'",
530530
])
@@ -598,7 +598,7 @@ def test_parens_in_expressions(self):
598598
# are added around it. But we shouldn't go from an invalid
599599
# expression to a valid one. The added parens are just
600600
# supposed to allow whitespace (including newlines).
601-
self.assertAllRaise(SyntaxError, 'invalid syntax',
601+
self.assertAllRaise(SyntaxError, 'f-string: invalid syntax',
602602
["f'{,}'",
603603
"f'{,}'", # this is (,), which is an error
604604
])
@@ -716,7 +716,7 @@ def test_lambda(self):
716716

717717
# lambda doesn't work without parens, because the colon
718718
# makes the parser think it's a format_spec
719-
self.assertAllRaise(SyntaxError, 'invalid syntax',
719+
self.assertAllRaise(SyntaxError, 'f-string: invalid syntax',
720720
["f'{lambda x:x}'",
721721
])
722722

@@ -1194,6 +1194,10 @@ def test_walrus(self):
11941194
self.assertEqual(f'{(x:=10)}', '10')
11951195
self.assertEqual(x, 10)
11961196

1197+
def test_invalid_syntax_error_message(self):
1198+
with self.assertRaisesRegex(SyntaxError, "f-string: invalid syntax"):
1199+
compile("f'{a $ b}'", "?", "exec")
1200+
11971201

11981202
if __name__ == '__main__':
11991203
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Prefix the error message with 'f-string: ', when parsing an f-string expression which throws a :exc:`SyntaxError`.

Parser/pegen.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,21 @@ _PyPegen_raise_error_known_location(Parser *p, PyObject *errtype,
391391
PyObject *tmp = NULL;
392392
p->error_indicator = 1;
393393

394+
if (p->start_rule == Py_fstring_input) {
395+
const char *fstring_msg = "f-string: ";
396+
Py_ssize_t len = strlen(fstring_msg) + strlen(errmsg);
397+
398+
char *new_errmsg = PyMem_RawMalloc(len + 1); // Lengths of both strings plus NULL character
399+
if (!new_errmsg) {
400+
return (void *) PyErr_NoMemory();
401+
}
402+
403+
// Copy both strings into new buffer
404+
memcpy(new_errmsg, fstring_msg, strlen(fstring_msg));
405+
memcpy(new_errmsg + strlen(fstring_msg), errmsg, strlen(errmsg));
406+
new_errmsg[len] = 0;
407+
errmsg = new_errmsg;
408+
}
394409
errstr = PyUnicode_FromFormatV(errmsg, va);
395410
if (!errstr) {
396411
goto error;
@@ -427,11 +442,17 @@ _PyPegen_raise_error_known_location(Parser *p, PyObject *errtype,
427442

428443
Py_DECREF(errstr);
429444
Py_DECREF(value);
445+
if (p->start_rule == Py_fstring_input) {
446+
PyMem_RawFree((void *)errmsg);
447+
}
430448
return NULL;
431449

432450
error:
433451
Py_XDECREF(errstr);
434452
Py_XDECREF(error_line);
453+
if (p->start_rule == Py_fstring_input) {
454+
PyMem_RawFree((void *)errmsg);
455+
}
435456
return NULL;
436457
}
437458

0 commit comments

Comments
 (0)