Skip to content

Commit cf57f4f

Browse files
[3.14] gh-137314: Fix incorrect treatment of format specs in raw fstrings (GH-137328) (#137344)
gh-137314: Fix incorrect treatment of format specs in raw fstrings (GH-137328) (cherry picked from commit 0153d82) Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>
1 parent 42b58cf commit cf57f4f

File tree

3 files changed

+42
-1
lines changed

3 files changed

+42
-1
lines changed

Lib/test/test_fstring.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1831,6 +1831,34 @@ def test_newlines_in_format_specifiers(self):
18311831
for case in valid_cases:
18321832
compile(case, "<string>", "exec")
18331833

1834+
def test_raw_fstring_format_spec(self):
1835+
# Test raw f-string format spec behavior (Issue #137314).
1836+
#
1837+
# Raw f-strings should preserve literal backslashes in format specifications,
1838+
# not interpret them as escape sequences.
1839+
class UnchangedFormat:
1840+
"""Test helper that returns the format spec unchanged."""
1841+
def __format__(self, format):
1842+
return format
1843+
1844+
# Test basic escape sequences
1845+
self.assertEqual(f"{UnchangedFormat():\xFF}", 'ÿ')
1846+
self.assertEqual(rf"{UnchangedFormat():\xFF}", '\\xFF')
1847+
1848+
# Test nested expressions with raw/non-raw combinations
1849+
self.assertEqual(rf"{UnchangedFormat():{'\xFF'}}", 'ÿ')
1850+
self.assertEqual(f"{UnchangedFormat():{r'\xFF'}}", '\\xFF')
1851+
self.assertEqual(rf"{UnchangedFormat():{r'\xFF'}}", '\\xFF')
1852+
1853+
# Test continuation character in format specs
1854+
self.assertEqual(f"""{UnchangedFormat():{'a'\
1855+
'b'}}""", 'ab')
1856+
self.assertEqual(rf"""{UnchangedFormat():{'a'\
1857+
'b'}}""", 'ab')
1858+
1859+
# Test multiple format specs in same raw f-string
1860+
self.assertEqual(rf"{UnchangedFormat():\xFF} {UnchangedFormat():\n}", '\\xFF \\n')
1861+
18341862

18351863
if __name__ == '__main__':
18361864
unittest.main()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fixed a regression where raw f-strings incorrectly interpreted
2+
escape sequences in format specifications. Raw f-strings now properly preserve
3+
literal backslashes in format specs, matching the behavior from Python 3.11.
4+
For example, ``rf"{obj:\xFF}"`` now correctly produces ``'\\xFF'`` instead of
5+
``'ÿ'``. Patch by Pablo Galindo.

Parser/action_helpers.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1404,7 +1404,15 @@ expr_ty _PyPegen_decoded_constant_from_token(Parser* p, Token* tok) {
14041404
if (PyBytes_AsStringAndSize(tok->bytes, &bstr, &bsize) == -1) {
14051405
return NULL;
14061406
}
1407-
PyObject* str = _PyPegen_decode_string(p, 0, bstr, bsize, tok);
1407+
1408+
// Check if we're inside a raw f-string for format spec decoding
1409+
int is_raw = 0;
1410+
if (INSIDE_FSTRING(p->tok)) {
1411+
tokenizer_mode *mode = TOK_GET_MODE(p->tok);
1412+
is_raw = mode->raw;
1413+
}
1414+
1415+
PyObject* str = _PyPegen_decode_string(p, is_raw, bstr, bsize, tok);
14081416
if (str == NULL) {
14091417
return NULL;
14101418
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy