Skip to content

[3.14] gh-137314: Fix incorrect treatment of format specs in raw fstrings (GH-137328) #137344

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions Lib/test/test_fstring.py
Original file line number Diff line number Diff line change
Expand Up @@ -1831,6 +1831,34 @@ def test_newlines_in_format_specifiers(self):
for case in valid_cases:
compile(case, "<string>", "exec")

def test_raw_fstring_format_spec(self):
# Test raw f-string format spec behavior (Issue #137314).
#
# Raw f-strings should preserve literal backslashes in format specifications,
# not interpret them as escape sequences.
class UnchangedFormat:
"""Test helper that returns the format spec unchanged."""
def __format__(self, format):
return format

# Test basic escape sequences
self.assertEqual(f"{UnchangedFormat():\xFF}", 'ÿ')
self.assertEqual(rf"{UnchangedFormat():\xFF}", '\\xFF')

# Test nested expressions with raw/non-raw combinations
self.assertEqual(rf"{UnchangedFormat():{'\xFF'}}", 'ÿ')
self.assertEqual(f"{UnchangedFormat():{r'\xFF'}}", '\\xFF')
self.assertEqual(rf"{UnchangedFormat():{r'\xFF'}}", '\\xFF')

# Test continuation character in format specs
self.assertEqual(f"""{UnchangedFormat():{'a'\
'b'}}""", 'ab')
self.assertEqual(rf"""{UnchangedFormat():{'a'\
'b'}}""", 'ab')

# Test multiple format specs in same raw f-string
self.assertEqual(rf"{UnchangedFormat():\xFF} {UnchangedFormat():\n}", '\\xFF \\n')


if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Fixed a regression where raw f-strings incorrectly interpreted
escape sequences in format specifications. Raw f-strings now properly preserve
literal backslashes in format specs, matching the behavior from Python 3.11.
For example, ``rf"{obj:\xFF}"`` now correctly produces ``'\\xFF'`` instead of
``'ÿ'``. Patch by Pablo Galindo.
10 changes: 9 additions & 1 deletion Parser/action_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1404,7 +1404,15 @@ expr_ty _PyPegen_decoded_constant_from_token(Parser* p, Token* tok) {
if (PyBytes_AsStringAndSize(tok->bytes, &bstr, &bsize) == -1) {
return NULL;
}
PyObject* str = _PyPegen_decode_string(p, 0, bstr, bsize, tok);

// Check if we're inside a raw f-string for format spec decoding
int is_raw = 0;
if (INSIDE_FSTRING(p->tok)) {
tokenizer_mode *mode = TOK_GET_MODE(p->tok);
is_raw = mode->raw;
}

PyObject* str = _PyPegen_decode_string(p, is_raw, bstr, bsize, tok);
if (str == NULL) {
return NULL;
}
Expand Down
Loading