From 4ef51fa75c17d4f027f2b73ff92be7a8b53eeb4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 8 Sep 2025 13:31:40 +0200 Subject: [PATCH 1/9] gh-138633: fix Sphinx references in `ssl` documentation (#138648) --- Doc/library/ssl.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 3ed1c515d86d85..0f2c2b89295cdf 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1195,11 +1195,11 @@ SSL sockets also have the following additional methods and attributes: Perform the SSL setup handshake. - If *block* is true and the timeout obtained by :meth:`~socket.gettimeout` + If *block* is true and the timeout obtained by :meth:`~socket.socket.gettimeout` is zero, the socket is set in blocking mode until the handshake is performed. .. versionchanged:: 3.4 - The handshake method also performs :func:`match_hostname` when the + The handshake method also performs :func:`!match_hostname` when the :attr:`~SSLContext.check_hostname` attribute of the socket's :attr:`~SSLSocket.context` is true. @@ -1209,7 +1209,7 @@ SSL sockets also have the following additional methods and attributes: .. versionchanged:: 3.7 Hostname or IP address is matched by OpenSSL during handshake. The - function :func:`match_hostname` is no longer used. In case OpenSSL + function :func:`!match_hostname` is no longer used. In case OpenSSL refuses a hostname or IP address, the handshake is aborted early and a TLS alert message is sent to the peer. @@ -2863,7 +2863,7 @@ This common check is automatically performed when .. versionchanged:: 3.7 Hostname matchings is now performed by OpenSSL. Python no longer uses - :func:`match_hostname`. + :func:`!match_hostname`. In server mode, if you want to authenticate your clients using the SSL layer (rather than using a higher-level authentication mechanism), you'll also have From 921f61bd82908ab245d6776068a366da152788d4 Mon Sep 17 00:00:00 2001 From: Adorilson Bezerra Date: Mon, 8 Sep 2025 13:02:36 +0100 Subject: [PATCH 2/9] Doc: Apply keyword role around finally (in sys module doc) (GH-138544) --- Doc/library/sys.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 30fd4db1fd1851..70d68c06187b60 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -523,8 +523,9 @@ always available. Unless explicitly noted otherwise, all variables are read-only Since :func:`exit` ultimately "only" raises an exception, it will only exit the process when called from the main thread, and the exception is not - intercepted. Cleanup actions specified by finally clauses of :keyword:`try` statements - are honored, and it is possible to intercept the exit attempt at an outer level. + intercepted. Cleanup actions specified by :keyword:`finally` clauses of + :keyword:`try` statements are honored, and it is possible to intercept the + exit attempt at an outer level. .. versionchanged:: 3.6 If an error occurs in the cleanup after the Python interpreter From 7a3bca50e08811070cc244109067c719ca970fc6 Mon Sep 17 00:00:00 2001 From: yihong Date: Mon, 8 Sep 2025 21:04:22 +0800 Subject: [PATCH 3/9] gh-138318, PyREPL: builtins should not be highlighted when used as attribute names (#138319) --- Lib/_pyrepl/utils.py | 5 +++- Lib/test/test_pyrepl/test_utils.py | 24 ++++++++++++++++++- ...-09-01-16-09-02.gh-issue-138318.t-WEN5.rst | 3 +++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-09-01-16-09-02.gh-issue-138318.t-WEN5.rst diff --git a/Lib/_pyrepl/utils.py b/Lib/_pyrepl/utils.py index fd788c8429e15b..c5d006afa7731f 100644 --- a/Lib/_pyrepl/utils.py +++ b/Lib/_pyrepl/utils.py @@ -208,7 +208,10 @@ def gen_colors_from_token_stream( ): span = Span.from_token(token, line_lengths) yield ColorSpan(span, "soft_keyword") - elif token.string in BUILTINS: + elif ( + token.string in BUILTINS + and not (prev_token and prev_token.exact_type == T.DOT) + ): span = Span.from_token(token, line_lengths) yield ColorSpan(span, "builtin") diff --git a/Lib/test/test_pyrepl/test_utils.py b/Lib/test/test_pyrepl/test_utils.py index 8ce1e5371386f0..05a4f329059835 100644 --- a/Lib/test/test_pyrepl/test_utils.py +++ b/Lib/test/test_pyrepl/test_utils.py @@ -1,6 +1,6 @@ from unittest import TestCase -from _pyrepl.utils import str_width, wlen, prev_next_window +from _pyrepl.utils import str_width, wlen, prev_next_window, gen_colors class TestUtils(TestCase): @@ -60,3 +60,25 @@ def gen_raise(): self.assertEqual(next(pnw), (3, 4, None)) with self.assertRaises(ZeroDivisionError): next(pnw) + + def test_gen_colors_keyword_highlighting(self): + cases = [ + # no highlights + ("a.set", [(".", "op")]), + ("obj.list", [(".", "op")]), + ("obj.match", [(".", "op")]), + ("b. \\\n format", [(".", "op")]), + # highlights + ("set", [("set", "builtin")]), + ("list", [("list", "builtin")]), + (" \n dict", [("dict", "builtin")]), + ] + for code, expected_highlights in cases: + with self.subTest(code=code): + colors = list(gen_colors(code)) + # Extract (text, tag) pairs for comparison + actual_highlights = [] + for color in colors: + span_text = code[color.span.start:color.span.end + 1] + actual_highlights.append((span_text, color.tag)) + self.assertEqual(actual_highlights, expected_highlights) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-09-01-16-09-02.gh-issue-138318.t-WEN5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-01-16-09-02.gh-issue-138318.t-WEN5.rst new file mode 100644 index 00000000000000..ce9456ddd10954 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-01-16-09-02.gh-issue-138318.t-WEN5.rst @@ -0,0 +1,3 @@ +The default REPL now avoids highlighting built-in names (for instance :class:`set` +or :func:`format`) when they are used as attribute names (for instance in ``value.set`` +or ``text.format``). From 59edf12705ca574040af266e044c7af69b5a75dd Mon Sep 17 00:00:00 2001 From: Christoph Walcher Date: Mon, 8 Sep 2025 15:42:54 +0200 Subject: [PATCH 4/9] gh-57911: Fix failing symlink test in tarfile (GH-138626) --- Lib/test/test_tarfile.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index e5466c3bf2a5e8..9892005787c8a6 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -3694,7 +3694,7 @@ def setUpClass(cls): else: raise AssertionError('Could not determine link resolution') else: - cls.dotdot_resolves_early = True + cls.dotdot_resolves_early = False @contextmanager def check_context(self, tar, filter, *, check_flag=True): @@ -3842,7 +3842,7 @@ def test_parent_symlink(self): arc.add('current', symlink_to='.') # effectively points to ./../ - if self.dotdot_resolves_early: + if self.dotdot_resolves_early and os_helper.can_symlink(): arc.add('parent', symlink_to='current/../..') else: arc.add('parent', symlink_to='current/..') From 4f0c267b40e52b83b2e1515aa0dd74eda31ae18a Mon Sep 17 00:00:00 2001 From: sobolevn Date: Mon, 8 Sep 2025 16:44:44 +0300 Subject: [PATCH 5/9] gh-138644: Update c-api docs of `PyInterpreterState` about PEP-684 (#138651) Co-authored-by: Peter Bierma --- Doc/c-api/init.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index b99988f743dcf2..bb9e08acee14c2 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1020,6 +1020,12 @@ code, or when embedding the Python interpreter: interpreter lock is also shared by all threads, regardless of to which interpreter they belong. + .. versionchanged:: 3.12 + + :pep:`684` introduced the possibility + of a :ref:`per-interpreter GIL `. + See :c:func:`Py_NewInterpreterFromConfig`. + .. c:type:: PyThreadState @@ -1711,6 +1717,8 @@ function. You can create and destroy them using the following functions: haven't been explicitly destroyed at that point. +.. _per-interpreter-gil: + A Per-Interpreter GIL --------------------- @@ -1722,7 +1730,7 @@ being blocked by other interpreters or blocking any others. Thus a single Python process can truly take advantage of multiple CPU cores when running Python code. The isolation also encourages a different approach to concurrency than that of just using threads. -(See :pep:`554`.) +(See :pep:`554` and :pep:`684`.) Using an isolated interpreter requires vigilance in preserving that isolation. That especially means not sharing any objects or mutable From c006a623e73d2368ec653e19c769706885161053 Mon Sep 17 00:00:00 2001 From: Aalaap Dey <65075436+axdeyy@users.noreply.github.com> Date: Mon, 8 Sep 2025 15:16:33 +0100 Subject: [PATCH 6/9] gh-138659: Typo in the gc module docstring (#138660) docs(gc): fix typo in get_threshold() docstring Removes a duplicate "the" from the docstring for the `gc.get_threshold()` function. --- Modules/gcmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 02839ca3c99bef..19b3f2a2eb6147 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -478,7 +478,7 @@ PyDoc_STRVAR(gc__doc__, "set_debug() -- Set debugging flags.\n" "get_debug() -- Get debugging flags.\n" "set_threshold() -- Set the collection thresholds.\n" -"get_threshold() -- Return the current the collection thresholds.\n" +"get_threshold() -- Return the current collection thresholds.\n" "get_objects() -- Return a list of all objects tracked by the collector.\n" "is_tracked() -- Returns true if a given object is tracked.\n" "is_finalized() -- Returns true if a given object has been already finalized.\n" From 1acb718ea215da7ff030f5457bdfa42c31ef39c1 Mon Sep 17 00:00:00 2001 From: Klaus Zimmermann Date: Mon, 8 Sep 2025 16:35:44 +0200 Subject: [PATCH 7/9] gh-133143: Add sys.abi_info (GH-137476) This makes information about the interpreter ABI more accessible. Co-authored-by: Petr Viktorin Co-authored-by: Victor Stinner Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/sys.rst | 45 ++++++++++++ Doc/whatsnew/3.15.rst | 7 ++ Lib/test/test_sys.py | 14 ++++ ...-08-06-16-55-44.gh-issue-133143.l7CI9v.rst | 1 + Python/sysmodule.c | 70 +++++++++++++++++++ 5 files changed, 137 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-08-06-16-55-44.gh-issue-133143.l7CI9v.rst diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 70d68c06187b60..34764a7e4f097b 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -11,6 +11,51 @@ interpreter and to functions that interact strongly with the interpreter. It is always available. Unless explicitly noted otherwise, all variables are read-only. +.. data:: abi_info + + .. versionadded:: next + + An object containing information about the ABI of the currently running + Python interpreter. + It should include information that affect the CPython ABI in ways that + require a specific build of the interpreter chosen from variants that can + co-exist on a single machine. + For example, it does not encode the base OS (Linux or Windows), but does + include pointer size since some systems support both 32- and 64-bit builds. + The available entries are the same on all platforms; + e.g. *pointer_size* is available even on 64-bit-only architectures. + + The following attributes are available: + + .. attribute:: abi_info.pointer_bits + + The width of pointers in bits, as an integer, + equivalent to ``8 * sizeof(void *)``. + Usually, this is ``32`` or ``64``. + + .. attribute:: abi_info.free_threaded + + A Boolean indicating whether the interpreter was built with + :term:`free threading` support. + This reflects either the presence of the :option:`--disable-gil` + :file:`configure` option (on Unix) + or setting the ``DisableGil`` property (on Windows). + + .. attribute:: abi_info.debug + + A Boolean indicating whether the interpreter was built in + :ref:`debug mode `. + This reflects either the presence of the :option:`--with-pydebug` + :file:`configure` option (on Unix) + or the ``Debug`` configuration (on Windows). + + .. attribute:: abi_info.byteorder + + A string indicating the native byte order, + either ``'big'`` or ``'little'``. + This is the same as the :data:`byteorder` attribute. + + .. data:: abiflags On POSIX systems where Python was built with the standard ``configure`` diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index b98ee202ec6db6..01f1f31647f5e3 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -460,6 +460,13 @@ ssl (Contributed by Ron Frederick in :gh:`138252`.) +sys +--- + +* Add :data:`sys.abi_info` namespace to improve access to ABI information. + (Contributed by Klaus Zimmermann in :gh:`137476`.) + + tarfile ------- diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index f89237931b7185..42672eb7912eba 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -739,6 +739,20 @@ def test_thread_info(self): elif sys.platform == "wasi": self.assertEqual(info.name, "pthread-stubs") + def test_abi_info(self): + info = sys.abi_info + self.assertEqual(len(info.__dict__), 4) + pointer_bits = 64 if sys.maxsize > 2**32 else 32 + self.assertEqual(info.pointer_bits, pointer_bits) + self.assertEqual(info.byteorder, sys.byteorder) + for attr, flag in [ + ("free_threaded", "Py_GIL_DISABLED"), + ("debug", "Py_DEBUG"), + ]: + self.assertEqual(getattr(info, attr, None), + bool(sysconfig.get_config_var(flag)), + f"for {attr}") + @unittest.skipUnless(support.is_emscripten, "only available on Emscripten") def test_emscripten_info(self): self.assertEqual(len(sys._emscripten_info), 4) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-06-16-55-44.gh-issue-133143.l7CI9v.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-06-16-55-44.gh-issue-133143.l7CI9v.rst new file mode 100644 index 00000000000000..eaffb4022c6770 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-06-16-55-44.gh-issue-133143.l7CI9v.rst @@ -0,0 +1 @@ +Add ``sys.abi_info`` object to make ABI information more easily accessible. diff --git a/Python/sysmodule.c b/Python/sysmodule.c index cc798f6ae5c034..95ab87589718ce 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3268,6 +3268,7 @@ PyDoc_STR( "\n\ Static objects:\n\ \n\ +abi_info -- Python ABI information.\n\ builtin_module_names -- tuple of module names built into this interpreter\n\ copyright -- copyright notice pertaining to this interpreter\n\ exec_prefix -- prefix used to find the machine-specific Python library\n\ @@ -3638,6 +3639,73 @@ make_impl_info(PyObject *version_info) return NULL; } + +static PyObject * +make_abi_info(void) +{ + // New entries should be added when needed for a supported platform, or (for + // enabling an unsupported one) by core dev consensus. Entries should be removed + // following PEP 387. + int res; + PyObject *abi_info, *value, *ns; + abi_info = PyDict_New(); + if (abi_info == NULL) { + goto error; + } + + value = PyLong_FromLong(sizeof(void *) * 8); + if (value == NULL) { + goto error; + } + res = PyDict_SetItemString(abi_info, "pointer_bits", value); + Py_DECREF(value); + if (res < 0) { + goto error; + } + +#ifdef Py_GIL_DISABLED + value = Py_True; +#else + value = Py_False; +#endif + res = PyDict_SetItemString(abi_info, "free_threaded", value); + if (res < 0) { + goto error; + } + +#ifdef Py_DEBUG + value = Py_True; +#else + value = Py_False; +#endif + res = PyDict_SetItemString(abi_info, "debug", value); + if (res < 0) { + goto error; + } + +#if PY_BIG_ENDIAN + value = PyUnicode_FromString("big"); +#else + value = PyUnicode_FromString("little"); +#endif + if (value == NULL) { + goto error; + } + res = PyDict_SetItemString(abi_info, "byteorder", value); + Py_DECREF(value); + if (res < 0) { + goto error; + } + + ns = _PyNamespace_New(abi_info); + Py_DECREF(abi_info); + return ns; + +error: + Py_DECREF(abi_info); + return NULL; +} + #ifdef __EMSCRIPTEN__ PyDoc_STRVAR(emscripten_info__doc__, @@ -3863,6 +3931,8 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) SET_SYS("thread_info", PyThread_GetInfo()); + SET_SYS("abi_info", make_abi_info()); + /* initialize asyncgen_hooks */ if (_PyStructSequence_InitBuiltin(interp, &AsyncGenHooksType, &asyncgen_hooks_desc) < 0) From c6f8b2fdb109941f70e0ea59a587734e39b04879 Mon Sep 17 00:00:00 2001 From: Shamil Date: Mon, 8 Sep 2025 18:20:46 +0300 Subject: [PATCH 8/9] gh-138665: Move `platform.invalidate_caches` docs (#138667) --- Doc/library/platform.rst | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst index 37df13f8a1eb8c..88affb5eea2b59 100644 --- a/Doc/library/platform.rst +++ b/Doc/library/platform.rst @@ -187,6 +187,14 @@ Cross platform .. versionchanged:: 3.9 :attr:`processor` is resolved late instead of immediately. +.. function:: invalidate_caches() + + Clear out the internal cache of information, such as the :func:`uname`. + This is typically useful when the platform's :func:`node` is changed + by an external process and one needs to retrieve the updated value. + + .. versionadded:: 3.14 + Windows platform ---------------- @@ -370,14 +378,3 @@ The following options are accepted: You can also pass one or more positional arguments (``terse``, ``nonaliased``) to explicitly control the output format. These behave similarly to their corresponding options. - -Miscellaneous -------------- - -.. function:: invalidate_caches() - - Clear out the internal cache of information, such as the :func:`uname`. - This is typically useful when the platform's :func:`node` is changed - by an external process and one needs to retrieve the updated value. - - .. versionadded:: 3.14 From 7d435cfde6bd2b4b7f313eb20b53a1777e6c56d3 Mon Sep 17 00:00:00 2001 From: Bruce Merry <1963944+bmerry@users.noreply.github.com> Date: Mon, 8 Sep 2025 18:09:52 +0200 Subject: [PATCH 9/9] gh-136234: Fix `SelectorSocketTransport.writelines` to be robust to connection loss (#136743) --- Lib/asyncio/selector_events.py | 7 +++++++ Lib/test/test_asyncio/test_selector_events.py | 16 ++++++++++++++++ ...025-07-17-16-12-23.gh-issue-136234.VmTxtj.rst | 2 ++ 3 files changed, 25 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-07-17-16-12-23.gh-issue-136234.VmTxtj.rst diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index 3505d4bb6bd1f7..a7e27ccf0aa856 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -1174,6 +1174,13 @@ def writelines(self, list_of_data): raise RuntimeError('unable to writelines; sendfile is in progress') if not list_of_data: return + + if self._conn_lost: + if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES: + logger.warning('socket.send() raised exception.') + self._conn_lost += 1 + return + self._buffer.extend([memoryview(data) for data in list_of_data]) self._write_ready() # If the entire buffer couldn't be written, register a write handler diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py index 9d77e7e5889d61..4bb5d4fb816a9a 100644 --- a/Lib/test/test_asyncio/test_selector_events.py +++ b/Lib/test/test_asyncio/test_selector_events.py @@ -854,6 +854,22 @@ def test_writelines_pauses_protocol(self): self.assertTrue(self.sock.send.called) self.assertTrue(self.loop.writers) + def test_writelines_after_connection_lost(self): + # GH-136234 + transport = self.socket_transport() + self.sock.send = mock.Mock() + self.sock.send.side_effect = ConnectionResetError + transport.write(b'data1') # Will fail immediately, causing connection lost + + transport.writelines([b'data2']) + self.assertFalse(transport._buffer) + self.assertFalse(self.loop.writers) + + test_utils.run_briefly(self.loop) # Allow _call_connection_lost to run + transport.writelines([b'data2']) + self.assertFalse(transport._buffer) + self.assertFalse(self.loop.writers) + @unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg') def test_write_sendmsg_full(self): data = memoryview(b'data') diff --git a/Misc/NEWS.d/next/Library/2025-07-17-16-12-23.gh-issue-136234.VmTxtj.rst b/Misc/NEWS.d/next/Library/2025-07-17-16-12-23.gh-issue-136234.VmTxtj.rst new file mode 100644 index 00000000000000..044a601c9170a1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-07-17-16-12-23.gh-issue-136234.VmTxtj.rst @@ -0,0 +1,2 @@ +Fix :meth:`asyncio.WriteTransport.writelines` to be robust to connection +failure, by using the same behavior as :meth:`~asyncio.WriteTransport.write`.