diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 2fe959f6c14f77..5839687b37c7b5 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1045,6 +1045,12 @@ def test_misformed_unicode_character_name(self): r"f'\N{'", r"f'\N{GREEK CAPITAL LETTER DELTA'", + # Malformed Unicode escapes in format specifiers + # are decoded through a separate parser path. + r"f'{x:\N}'", + r"f'{x:\N{'", + r"f'{x:{y}\N{'", + # Here are the non-f-string versions, # which should give the same errors. r"'\N'", diff --git a/Lib/test/test_tstring.py b/Lib/test/test_tstring.py index 20a5083f60d11a..bda08129938aa3 100644 --- a/Lib/test/test_tstring.py +++ b/Lib/test/test_tstring.py @@ -354,6 +354,11 @@ def test_syntax_errors(self): with self.subTest(case), self.assertRaisesRegex(SyntaxError, err): eval(case) + # Malformed Unicode escapes in format specifiers are decoded + # through a separate parser path. + with self.assertRaises(SyntaxError): + eval(r"t'{x:\N}'") + def test_runtime_errors(self): # Test missing variables with self.assertRaises(NameError): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-21-16-28-16.gh-issue-157890.OzIanA.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-21-16-28-16.gh-issue-157890.OzIanA.rst new file mode 100644 index 00000000000000..cc2164dca8a4c6 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-21-16-28-16.gh-issue-157890.OzIanA.rst @@ -0,0 +1,2 @@ +Raise :exc:`SyntaxError` instead of :exc:`UnicodeDecodeError` for malformed +Unicode character name escapes in f-string and t-string format specifiers. diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 88a9df98aa5b62..aa787ef4df9398 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1504,8 +1504,9 @@ expr_ty _PyPegen_decoded_constant_from_token(Parser* p, Token* tok) { int is_raw = tok->is_raw; - PyObject* str = _PyPegen_decode_string(p, is_raw, bstr, bsize, tok); + PyObject *str = _PyPegen_decode_string(p, is_raw, bstr, bsize, tok); if (str == NULL) { + _Pypegen_raise_decode_error(p); return NULL; } if (_PyArena_AddPyObject(p->arena, str) < 0) {