Skip to content
Merged
10 changes: 9 additions & 1 deletion Doc/c-api/init.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <per-interpreter-gil>`.
See :c:func:`Py_NewInterpreterFromConfig`.


.. c:type:: PyThreadState

Expand Down Expand Up @@ -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
---------------------

Expand All @@ -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
Expand Down
19 changes: 8 additions & 11 deletions Doc/library/platform.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
----------------
Expand Down Expand Up @@ -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
8 changes: 4 additions & 4 deletions Doc/library/ssl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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.

Expand Down Expand Up @@ -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
Expand Down
50 changes: 48 additions & 2 deletions Doc/library/sys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <debug-build>`.
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``
Expand Down Expand Up @@ -523,8 +568,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
Expand Down
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
-------

Expand Down
5 changes: 4 additions & 1 deletion Lib/_pyrepl/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
7 changes: 7 additions & 0 deletions Lib/asyncio/selector_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions Lib/test/test_asyncio/test_selector_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
24 changes: 23 additions & 1 deletion Lib/test/test_pyrepl/test_utils.py
Original file line number Diff line number Diff line change
@@ -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):
Expand Down Expand Up @@ -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)
14 changes: 14 additions & 0 deletions Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_tarfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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/..')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add ``sys.abi_info`` object to make ABI information more easily accessible.
Original file line number Diff line number Diff line change
@@ -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``).
Original file line number Diff line number Diff line change
@@ -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`.
2 changes: 1 addition & 1 deletion Modules/gcmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading
Loading