Skip to content

Commit e39bd48

Browse files
Merge branch 'main' into tkinter-tk-print
2 parents aa50e0b + c22e9c9 commit e39bd48

202 files changed

Lines changed: 9036 additions & 3431 deletions

File tree

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/c-api/float.rst

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,6 @@ most likely :exc:`OverflowError`).
233233
234234
Pack a C double as the IEEE 754 binary64 double precision format.
235235
236-
.. impl-detail::
237-
This function always succeeds in CPython.
238-
239236
240237
Unpack functions
241238
^^^^^^^^^^^^^^^^
@@ -251,9 +248,6 @@ Return value: The unpacked double. On error, this is ``-1.0`` and
251248
:c:func:`PyErr_Occurred` is true (and an exception is set, most likely
252249
:exc:`OverflowError`).
253250
254-
.. impl-detail::
255-
These functions always succeed in CPython.
256-
257251
.. c:function:: double PyFloat_Unpack2(const char *p, int le)
258252
259253
Unpack the IEEE 754 binary16 half-precision format as a C double.

Doc/deprecations/pending-removal-in-3.21.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,8 @@ Pending removal in Python 3.21
2323
* Soft-deprecated since Python 3.15, using ``'F'`` and ``'D'`` type codes are now
2424
deprecated. These codes will be removed in Python 3.21. Use instead
2525
two-letter forms ``'Zf'`` and ``'Zd'``.
26+
27+
* :mod:`tempfile`:
28+
29+
* ``tempfile._TemporaryFileWrapper`` will be removed in Python 3.21. Use the
30+
public :class:`tempfile.TemporaryFileWrapper` instead.

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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,18 @@ On Windows, ``cpXXX`` codecs are available for all code pages.
10871087
But only codecs listed in the following table are guaranteed to exist on
10881088
other platforms.
10891089

1090+
On platforms that provide the C library's :manpage:`iconv(3)` function
1091+
(such as those using the GNU C Library),
1092+
every encoding known to ``iconv`` for which Python has no built-in codec
1093+
is available as well.
1094+
Such an encoding is looked up by its ``iconv`` name (for example ``cp1133``).
1095+
Prefixing the name with ``iconv:`` forces the use of the ``iconv``-based codec
1096+
even when a built-in codec of the same name exists (for example ``iconv:latin1``),
1097+
which is mostly useful for testing.
1098+
1099+
.. versionchanged:: next
1100+
Added support for encodings provided by the C library's ``iconv``.
1101+
10901102
.. impl-detail::
10911103

10921104
Some common encodings can bypass the codecs lookup machinery to
@@ -1438,6 +1450,14 @@ encodings.
14381450
| | | code actually uses UTF-8 |
14391451
| | | by default. |
14401452
+--------------------+---------+---------------------------+
1453+
| utf-7-imap | mUTF-7 | Modified UTF-7 encoding |
1454+
| | | of :rfc:`3501` for IMAP4 |
1455+
| | | mailbox names. Only |
1456+
| | | ``errors='strict'`` is |
1457+
| | | supported. |
1458+
| | | |
1459+
| | | .. versionadded:: next |
1460+
+--------------------+---------+---------------------------+
14411461

14421462
.. versionchanged:: 3.8
14431463
"unicode_internal" codec is removed.

Doc/library/email.utils.rst

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ of the new API.
7070
Add *strict* optional parameter and reject malformed inputs by default.
7171

7272

73-
.. function:: formataddr(pair, charset='utf-8')
73+
.. function:: formataddr(pair, charset='utf-8', *, strict=True)
7474

7575
The inverse of :meth:`parseaddr`, this takes a 2-tuple of the form ``(realname,
7676
email_address)`` and returns the string value suitable for a :mailheader:`To` or
@@ -82,9 +82,16 @@ of the new API.
8282
characters. Can be an instance of :class:`str` or a
8383
:class:`~email.charset.Charset`. Defaults to ``utf-8``.
8484

85+
If *strict* is true (the default), raise :exc:`ValueError` for inputs that
86+
contain CR or LF, which are not allowed in an email address. Set *strict*
87+
to ``False`` to allow non-strict inputs.
88+
8589
.. versionchanged:: 3.3
8690
Added the *charset* option.
8791

92+
.. versionchanged:: next
93+
Added the *strict* parameter.
94+
8895

8996
.. function:: getaddresses(fieldvalues, *, strict=True)
9097

0 commit comments

Comments
 (0)