Skip to content

Commit d07a812

Browse files
generatedunixname1734921407115435meta-codesync[bot]
authored andcommitted
Sync pre-release CPython main branch from GitHub (2026-07-09)
Summary: Imported python/cpython `3.16.0a0` from upstream rev [`6d38668`](https://www.github.com/python/cpython/commit/6d386684ad69f42cb57c72fe0e0ffcec82ec7e12) (committed 2026-07-09 03:40:18+00:00). # Commit Info - Base: (`3.16.0a0`) - [`4572903`](https://www.github.com/python/cpython/commit/45729033bff28f8abc36c42e802cb2853c205737) (commit date: 2026-07-08 00:40:54+00:00) - Imported: (`3.16.0a0`) - [`6d38668`](https://www.github.com/python/cpython/commit/6d386684ad69f42cb57c72fe0e0ffcec82ec7e12) (commit date: 2026-07-09 03:40:18+00:00) # Noteworthy file changes - Stdlib files (1 added) - Test files (2 added) - Low-signal files (11 added) (NEWS.d, docs, .github) Complete list of added/removed files: https://www.internalfb.com/intern/everpaste/?color=0&handle=GHMY6yQeI0hLHMsGAKtiFOkuhjUybr0LAAAz Differential Revision: D111189779 fbshipit-source-id: 379703241b02d48048e6219436f3ca03e439e330
1 parent 3632b89 commit d07a812

52 files changed

Lines changed: 1384 additions & 187 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/reusable-san.yml

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ permissions:
1717

1818
env:
1919
FORCE_COLOR: 1
20+
OPENSSL_VER: 3.5.7
2021

2122
jobs:
2223
build-san-reusable:
@@ -38,28 +39,55 @@ jobs:
3839
run: |
3940
sudo ./.github/workflows/posix-deps-apt.sh
4041
# On ubuntu-26.04 image, clang is clang-21 by default
41-
42-
if [ "${SANITIZER}" = "TSan" ]; then
43-
# Reduce ASLR to avoid TSan crashing
44-
sudo sysctl -w vm.mmap_rnd_bits=28
45-
fi
46-
47-
- name: Sanitizer option setup
48-
run: |
49-
if [ "${SANITIZER}" = "TSan" ]; then
50-
echo "TSAN_OPTIONS=${SAN_LOG_OPTION} suppressions=${GITHUB_WORKSPACE}/Tools/tsan/suppressions${{
51-
fromJSON(inputs.free-threading)
52-
&& '_free_threading'
53-
|| ''
54-
}}.txt handle_segv=0" >> "$GITHUB_ENV"
55-
else
56-
echo "UBSAN_OPTIONS=${SAN_LOG_OPTION} halt_on_error=1 suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" >> "$GITHUB_ENV"
57-
fi
5842
echo "CC=clang" >> "$GITHUB_ENV"
5943
echo "CXX=clang++" >> "$GITHUB_ENV"
44+
- name: TSan option setup
45+
if: inputs.sanitizer == 'TSan'
46+
run: |
47+
sudo sysctl -w vm.mmap_rnd_bits=28 # Reduce ASLR to avoid TSan crashing
48+
49+
echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV"
50+
echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV"
51+
echo "TSAN_OPTIONS=${SAN_LOG_OPTION} suppressions=${GITHUB_WORKSPACE}/Tools/tsan/suppressions${SUPPRESSIONS_SUFFIX}.txt handle_segv=0" >> "$GITHUB_ENV"
6052
env:
61-
SANITIZER: ${{ inputs.sanitizer }}
6253
SAN_LOG_OPTION: log_path=${{ github.workspace }}/san_log
54+
SUPPRESSIONS_SUFFIX: >-
55+
${{
56+
fromJSON(inputs.free-threading)
57+
&& '_free_threading'
58+
|| ''
59+
}}
60+
- name: UBSan option setup
61+
if: inputs.sanitizer != 'TSan'
62+
run: >-
63+
echo
64+
"UBSAN_OPTIONS=${SAN_LOG_OPTION}
65+
halt_on_error=1
66+
suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt"
67+
>> "$GITHUB_ENV"
68+
env:
69+
SAN_LOG_OPTION: log_path=${{ github.workspace }}/san_log
70+
- name: Add ccache to PATH
71+
run: |
72+
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
73+
- name: 'Restore OpenSSL build (TSan)'
74+
id: cache-openssl
75+
if: inputs.sanitizer == 'TSan'
76+
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
77+
with:
78+
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
79+
key: ${{ env.IMAGE_OS_VERSION }}-multissl-openssl-tsan-${{ env.OPENSSL_VER }}
80+
- name: Install OpenSSL (TSan)
81+
if: >-
82+
inputs.sanitizer == 'TSan'
83+
&& steps.cache-openssl.outputs.cache-hit != 'true'
84+
run: >-
85+
python3 Tools/ssl/multissltests.py
86+
--steps=library
87+
--base-directory="${MULTISSL_DIR}"
88+
--openssl="${OPENSSL_VER}"
89+
--system=Linux
90+
--tsan
6391
- name: Configure CPython
6492
run: >-
6593
./configure
@@ -70,6 +98,7 @@ jobs:
7098
|| '--with-undefined-behavior-sanitizer --with-strict-overflow'
7199
}}
72100
--with-pydebug
101+
${{ inputs.sanitizer == 'TSan' && '--with-openssl="$OPENSSL_DIR" --with-openssl-rpath=auto' || '' }}
73102
${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
74103
- name: Build CPython
75104
run: make -j4

Doc/library/asyncio-graph.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
.. _asyncio-graph:
55

66
========================
7-
Call Graph Introspection
7+
Call graph introspection
88
========================
99

1010
**Source code:** :source:`Lib/asyncio/graph.py`
@@ -17,6 +17,12 @@ a suspended *future*. These utilities and the underlying machinery
1717
can be used from within a Python program or by external profilers
1818
and debuggers.
1919

20+
.. seealso::
21+
22+
:ref:`asyncio-introspection-tools`
23+
Command-line tools for inspecting tasks in another running Python
24+
process.
25+
2026
.. versionadded:: 3.14
2127

2228

Doc/library/asyncio-tools.rst

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
.. currentmodule:: asyncio
2+
3+
.. _asyncio-introspection-tools:
4+
5+
================================
6+
Command-line introspection tools
7+
================================
8+
9+
**Source code:** :source:`Lib/asyncio/tools.py`
10+
11+
-------------------------------------
12+
13+
The :mod:`!asyncio` module can be invoked as a script via ``python -m
14+
asyncio`` to inspect the task graph of another running Python process without
15+
modifying it or restarting it. The :mod:`!asyncio.tools` submodule implements
16+
this interface.
17+
18+
The following commands inspect the process identified by ``PID``:
19+
20+
.. code-block:: shell-session
21+
22+
$ python -m asyncio pstree [--retries N] PID
23+
$ python -m asyncio ps [--retries N] PID
24+
25+
The commands read the target process state without executing any code in it.
26+
They are only available on supported platforms and may require permission to
27+
inspect another process. See the :ref:`permission-requirements <permission-requirements>` for details.
28+
29+
.. seealso::
30+
31+
:ref:`asyncio-graph`
32+
Programmatic APIs for inspecting the async call graph of a task or
33+
future in the current process.
34+
35+
The command examples below use this program, which creates a task hierarchy
36+
suitable for inspection and prints its process ID:
37+
38+
.. code-block:: python
39+
:caption: example.py
40+
41+
import asyncio
42+
import os
43+
44+
async def play(track):
45+
await asyncio.sleep(3600)
46+
print(f"🎵 Finished: {track}")
47+
48+
async def album(name, tracks):
49+
async with asyncio.TaskGroup() as tg:
50+
for track in tracks:
51+
tg.create_task(play(track), name=track)
52+
53+
async def main():
54+
print(f"PID: {os.getpid()}")
55+
async with asyncio.TaskGroup() as tg:
56+
tg.create_task(
57+
album("Sundowning", ["TNDNBTG", "Levitate"]),
58+
name="Sundowning",
59+
)
60+
tg.create_task(
61+
album("TMBTE", ["DYWTYLM", "Aqua Regia"]),
62+
name="TMBTE",
63+
)
64+
65+
asyncio.run(main())
66+
67+
Run the program in one terminal and leave it running:
68+
69+
.. code-block:: shell-session
70+
71+
$ python example.py
72+
PID: 12345
73+
74+
Then pass the printed process ID to the commands from another terminal.
75+
Thread IDs, task IDs, file paths, and line numbers vary between runs and
76+
source layouts.
77+
78+
.. versionadded:: 3.14
79+
80+
Command-line options
81+
====================
82+
83+
.. option:: pstree PID
84+
85+
Display task and coroutine relationships as a tree. Each task is shown
86+
with its full coroutine stack, nested under the task (if any) that is
87+
awaiting it. This subcommand is useful for quickly identifying which branch
88+
of a task hierarchy is blocked and where in its coroutine stack execution
89+
has paused:
90+
91+
.. code-block:: shell-session
92+
93+
$ python -m asyncio pstree 12345
94+
└── (T) Task-1
95+
└── main example.py:12
96+
└── TaskGroup.__aexit__ Lib/asyncio/taskgroups.py:75
97+
└── TaskGroup._aexit Lib/asyncio/taskgroups.py:124
98+
├── (T) Sundowning
99+
│ └── album example.py:7
100+
│ └── TaskGroup.__aexit__ Lib/asyncio/taskgroups.py:75
101+
│ └── TaskGroup._aexit Lib/asyncio/taskgroups.py:124
102+
│ ├── (T) TNDNBTG
103+
│ │ └── play example.py:4
104+
│ │ └── sleep Lib/asyncio/tasks.py:702
105+
│ └── (T) Levitate
106+
│ └── play example.py:4
107+
│ └── sleep Lib/asyncio/tasks.py:702
108+
└── (T) TMBTE
109+
└── album example.py:7
110+
└── TaskGroup.__aexit__ Lib/asyncio/taskgroups.py:75
111+
└── TaskGroup._aexit Lib/asyncio/taskgroups.py:124
112+
├── (T) DYWTYLM
113+
│ └── play example.py:4
114+
│ └── sleep Lib/asyncio/tasks.py:702
115+
└── (T) Aqua Regia
116+
└── play example.py:4
117+
└── sleep Lib/asyncio/tasks.py:702
118+
119+
If the await graph contains a cycle, ``pstree`` reports an error instead
120+
of printing a tree. A cycle in the await graph is unusual and typically
121+
indicates a programming error:
122+
123+
.. code-block:: shell-session
124+
125+
$ python -m asyncio pstree 12345
126+
ERROR: await-graph contains cycles - cannot print a tree!
127+
128+
cycle: Task-2 → Task-3 → Task-2
129+
130+
.. option:: ps PID
131+
132+
Display a flat table of all pending tasks in the process *PID*. Each row
133+
shows the event-loop thread ID, task ID and name, coroutine stack, and the
134+
awaiting task's stack, name, and ID, if any.
135+
136+
This subcommand prints all tasks regardless of whether the await graph
137+
contains cycles:
138+
139+
.. code-block:: shell-session
140+
141+
$ python -m asyncio ps 12345
142+
tid task id task name coroutine stack awaiter chain awaiter name awaiter id
143+
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
144+
18445801 0x10a456060 Task-1 TaskGroup._aexit -> TaskGroup.__aexit__ -> main 0x0
145+
18445801 0x10a439f60 Sundowning TaskGroup._aexit -> TaskGroup.__aexit__ -> album TaskGroup._aexit -> TaskGroup.__aexit__ -> main Task-1 0x10a456060
146+
18445801 0x10a439d70 TMBTE TaskGroup._aexit -> TaskGroup.__aexit__ -> album TaskGroup._aexit -> TaskGroup.__aexit__ -> main Task-1 0x10a456060
147+
18445801 0x10a2a3a80 TNDNBTG sleep -> play TaskGroup._aexit -> TaskGroup.__aexit__ -> album Sundowning 0x10a439f60
148+
18445801 0x10a2a38a0 Levitate sleep -> play TaskGroup._aexit -> TaskGroup.__aexit__ -> album Sundowning 0x10a439f60
149+
18445801 0x10a2d7150 DYWTYLM sleep -> play TaskGroup._aexit -> TaskGroup.__aexit__ -> album TMBTE 0x10a439d70
150+
18445801 0x10a6bdaa0 Aqua Regia sleep -> play TaskGroup._aexit -> TaskGroup.__aexit__ -> album TMBTE 0x10a439d70
151+
152+
.. option:: --retries N
153+
154+
Retry failed attempts to inspect the target process up to *N* times. This
155+
can help when the target process changes while its state is being read.
156+
157+
.. versionadded:: 3.15

Doc/library/asyncio.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ asyncio provides a set of **high-level** APIs to:
4747

4848
* :ref:`synchronize <asyncio-sync>` concurrent code;
4949

50+
For **introspection**, asyncio provides APIs and tools for:
51+
52+
* inspecting the :ref:`async call graph <asyncio-graph>` of tasks and futures;
53+
54+
* inspecting tasks in another running Python process with
55+
:ref:`command-line tools <asyncio-introspection-tools>`;
56+
5057
Additionally, there are **low-level** APIs for
5158
*library and framework developers* to:
5259

@@ -108,7 +115,13 @@ for full functionality and the latest features.
108115
asyncio-subprocess.rst
109116
asyncio-queue.rst
110117
asyncio-exceptions.rst
118+
119+
.. toctree::
120+
:caption: Introspection APIs
121+
:maxdepth: 1
122+
111123
asyncio-graph.rst
124+
asyncio-tools.rst
112125

113126
.. toctree::
114127
:caption: Low-level APIs

Doc/library/codecs.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,6 +1438,14 @@ encodings.
14381438
| | | code actually uses UTF-8 |
14391439
| | | by default. |
14401440
+--------------------+---------+---------------------------+
1441+
| utf-7-imap | mUTF-7 | Modified UTF-7 encoding |
1442+
| | | of :rfc:`3501` for IMAP4 |
1443+
| | | mailbox names. Only |
1444+
| | | ``errors='strict'`` is |
1445+
| | | supported. |
1446+
| | | |
1447+
| | | .. versionadded:: next |
1448+
+--------------------+---------+---------------------------+
14411449

14421450
.. versionchanged:: 3.8
14431451
"unicode_internal" codec is removed.

Doc/library/ipaddress.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,35 @@ dictionaries.
718718
.. deprecated:: 3.7
719719
It uses the same ordering and comparison algorithm as "<", "==", and ">"
720720

721+
.. method:: next_network(next_prefix=None)
722+
723+
Finds the next closest network of prefix size *next_prefix*. If
724+
*next_prefix=None*, then the current network prefix will be used.
725+
Returns a single network object.
726+
727+
Raises :exc:`ValueError` if *next_prefix* is out of range or no further
728+
network of the requested size exists.
729+
730+
>>> IPv4Network('192.0.2.0/24').next_network()
731+
IPv4Network('192.0.3.0/24')
732+
>>> IPv4Network('192.0.2.0/24').next_network(next_prefix=25)
733+
IPv4Network('192.0.3.0/25')
734+
>>> IPv4Network('192.0.2.0/24').next_network(next_prefix=23)
735+
IPv4Network('192.0.4.0/23')
736+
>>> IPv4Network('192.0.80.0/22').next_network(next_prefix=18)
737+
IPv4Network('192.0.128.0/18')
738+
>>> IPv4Network('192.0.80.0/22').next_network(next_prefix=50)
739+
Traceback (most recent call last):
740+
File "<stdin>", line 1, in <module>
741+
raise ValueError(
742+
ValueError: next prefix must be between 1 and 32
743+
>>> IPv4Network('255.255.255.0/24').next_network()
744+
Traceback (most recent call last):
745+
File "<stdin>", line 1, in <module>
746+
raise ValueError(
747+
ValueError: out of address space, cannot make another /24 network
748+
749+
.. versionadded:: 3.16
721750

722751
.. class:: IPv6Network(address, strict=True)
723752

@@ -790,6 +819,7 @@ dictionaries.
790819
.. method:: supernet(prefixlen_diff=1, new_prefix=None)
791820
.. method:: subnet_of(other)
792821
.. method:: supernet_of(other)
822+
.. method:: next_network(next_prefix=None)
793823
.. method:: compare_networks(other)
794824

795825
Refer to the corresponding attribute documentation in

Doc/library/tkinter.font.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ The different font weights and slants are:
7474
requested ones because of platform limitations.
7575
With no *option*, return a dictionary of all the attributes; if *option*
7676
is given, return the value of that single attribute.
77+
The attributes are resolved on the display of the *displayof* widget,
78+
or the main application window if it is not specified.
7779

7880
.. method:: cget(option)
7981

@@ -97,7 +99,11 @@ The different font weights and slants are:
9799

98100
.. method:: copy()
99101

100-
Return new instance of the current font.
102+
Return a distinct copy of the current font:
103+
a new named font with the same attributes but a different name,
104+
which can be reconfigured independently of the original.
105+
If the current font wraps a font description,
106+
the copy is instead a named font with its resolved attributes.
101107

102108
.. method:: measure(text, displayof=None)
103109

Doc/reference/import.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,15 @@ shared libraries (e.g. ``.so`` files). When supported by the :mod:`zipimport`
665665
module in the standard library, the default path entry finders also handle
666666
loading all of these file types (other than shared libraries) from zipfiles.
667667

668+
Within a single :term:`path entry`, the default path entry finders check for a
669+
:term:`regular package` first, then for extension modules, then for source
670+
files, and finally for bytecode files. For example, if the same directory
671+
contains both ``spam/__init__.py`` and ``spam.py``, ``import spam`` will
672+
import the package from ``spam/__init__.py``. A directory without an
673+
``__init__.py`` file is treated as a :term:`namespace package` portion only if
674+
no matching module is found. Note that this does not override the order of the
675+
:term:`import path`.
676+
668677
Path entries need not be limited to file system locations. They can refer to
669678
URLs, database queries, or any other location that can be specified as a
670679
string.

0 commit comments

Comments
 (0)