From 0153d82a5ab0c6ac16c046bdd4438ea11b58d59d Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Sun, 3 Aug 2025 17:10:51 +0100 Subject: [PATCH 1/4] gh-137314: Fix incorrect treatment of format specs in raw fstrings (#137328) --- Lib/test/test_fstring.py | 28 +++++++++++++++++++ ...-08-02-23-04-57.gh-issue-137314.wjEdzD.rst | 5 ++++ Parser/action_helpers.c | 10 ++++++- 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-08-02-23-04-57.gh-issue-137314.wjEdzD.rst diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index b41e02c3a16379..41cefe0e286d50 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1831,6 +1831,34 @@ def test_newlines_in_format_specifiers(self): for case in valid_cases: compile(case, "", "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() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-02-23-04-57.gh-issue-137314.wjEdzD.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-02-23-04-57.gh-issue-137314.wjEdzD.rst new file mode 100644 index 00000000000000..09d0c3e68fc1ed --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-02-23-04-57.gh-issue-137314.wjEdzD.rst @@ -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. diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index ebc94715b6f361..0763866576733f 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -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; } From 1612dcbafe763014deefd679fe75ac5831a14a43 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 3 Aug 2025 19:41:12 +0300 Subject: [PATCH 2/4] gh-137341: Remove more word duplications (GH-137342) --- Doc/c-api/object.rst | 4 ++-- Doc/library/urllib.request.rst | 2 +- Doc/whatsnew/3.15.rst | 2 +- Lib/asyncio/base_events.py | 4 ++-- Lib/test/libregrtest/utils.py | 2 +- Lib/test/support/__init__.py | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 55f0d0f9fb7ff8..78599e704b1317 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -197,7 +197,7 @@ Object Protocol in favour of using :c:func:`PyObject_DelAttr`, but there are currently no plans to remove it. - The function must not be called with ``NULL`` *v* and an an exception set. + The function must not be called with a ``NULL`` *v* and an exception set. This case can arise from forgetting ``NULL`` checks and would delete the attribute. @@ -214,7 +214,7 @@ Object Protocol If *v* is ``NULL``, the attribute is deleted, but this feature is deprecated in favour of using :c:func:`PyObject_DelAttrString`. - The function must not be called with ``NULL`` *v* and an an exception set. + The function must not be called with a ``NULL`` *v* and an exception set. This case can arise from forgetting ``NULL`` checks and would delete the attribute. diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst index e514b98fc5d553..5f796578eaa64e 100644 --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -837,7 +837,7 @@ The following attribute and methods should only be used by classes derived from 1. a :class:`Request` object, #. a file-like object with the HTTP error body, #. the three-digit code of the error, as a string, - #. the user-visible explanation of the code, as as string, and + #. the user-visible explanation of the code, as a string, and #. the headers of the error, as a mapping object. Return values and exceptions raised should be the same as those of diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 010f6ce7f50e1e..e716d7bb0f2a5c 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -183,7 +183,7 @@ Other language changes compatibility between versions of Python, ensure that an explicit ``encoding`` argument is always provided. The :ref:`opt-in encoding warning ` can be used to identify code that may be affected by this change. - The special special ``encoding='locale'`` argument uses the current locale + The special ``encoding='locale'`` argument uses the current locale encoding, and has been supported since Python 3.10. To retain the previous behaviour, Python's UTF-8 mode may be disabled with diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 520d4b398545bf..8cbb71f708537f 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -636,7 +636,7 @@ def _check_running(self): def _run_forever_setup(self): """Prepare the run loop to process events. - This method exists so that custom custom event loop subclasses (e.g., event loops + This method exists so that custom event loop subclasses (e.g., event loops that integrate a GUI event loop with Python's event loop) have access to all the loop setup logic. """ @@ -656,7 +656,7 @@ def _run_forever_setup(self): def _run_forever_cleanup(self): """Clean up after an event loop finishes the looping over events. - This method exists so that custom custom event loop subclasses (e.g., event loops + This method exists so that custom event loop subclasses (e.g., event loops that integrate a GUI event loop with Python's event loop) have access to all the loop cleanup logic. """ diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py index 72b8ea89e62ee0..d94fb84a743828 100644 --- a/Lib/test/libregrtest/utils.py +++ b/Lib/test/libregrtest/utils.py @@ -536,7 +536,7 @@ def normalize_test_name(test_full_name: str, *, if is_error and short_name in _TEST_LIFECYCLE_HOOKS: if test_full_name.startswith(('setUpModule (', 'tearDownModule (')): # if setUpModule() or tearDownModule() failed, don't filter - # tests with the test file name, don't use use filters. + # tests with the test file name, don't use filters. return None # This means that we have a failure in a life-cycle hook, diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index cea2f09aae5d51..29cf32966d4e4a 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1686,7 +1686,7 @@ def check__all__(test_case, module, name_of_module=None, extra=(), 'module'. The 'name_of_module' argument can specify (as a string or tuple thereof) - what module(s) an API could be defined in in order to be detected as a + what module(s) an API could be defined in order to be detected as a public API. One case for this is when 'module' imports part of its public API from other modules, possibly a C backend (like 'csv' and its '_csv'). From 13e21b2fd6343ba8309ed857a2cbf6d6995ca5f2 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sun, 3 Aug 2025 20:32:46 +0200 Subject: [PATCH 3/4] GH-136155: Use ``sphinxext-opengraph`` v0.11.0 (#137348) --- Doc/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/requirements.txt b/Doc/requirements.txt index a2960ea9aa0203..924e218c9f67d9 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -11,7 +11,7 @@ sphinx~=8.2.0 blurb -sphinxext-opengraph~=0.10.0 +sphinxext-opengraph~=0.11.0 sphinx-notfound-page~=1.0.0 # The theme used by the documentation is stored separately, so we need From 406dc714f6b4dbc18d4e5119a10621386bccbee3 Mon Sep 17 00:00:00 2001 From: Kliment Lamonov Date: Sun, 3 Aug 2025 21:43:13 +0300 Subject: [PATCH 4/4] gh-136567: Add information about lost prefixes to `Tools/cases_generator/interpreter_definition.md` (#136780) --- Tools/cases_generator/interpreter_definition.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Tools/cases_generator/interpreter_definition.md b/Tools/cases_generator/interpreter_definition.md index 72020133738fa5..29e4e74da72154 100644 --- a/Tools/cases_generator/interpreter_definition.md +++ b/Tools/cases_generator/interpreter_definition.md @@ -174,7 +174,13 @@ list of annotations and their meanings are as follows: * `override`. For external use by other interpreter definitions to override the current instruction definition. * `pure`. This instruction has no side effects. -* 'tierN'. This instruction is only used by the tier N interpreter. +* `tierN`. This instruction is only used by the tier N interpreter. +* `specializing`. A prefix for an instructions related to adaptive interpreter. +* `replaced`. This instruction will be replaced in the final bytecode by its directed + version (either forward or backward). +* `register`. Currently does nothing. +* `replicate(N)`. Replicate the instruction N times to store the oparg "inside" the instruction. +* `no_save_ip`. This instruction does not affect the instruction pointer. ### Special functions/macros