Skip to content

Commit 2675c93

Browse files
authored
Merge branch 'main' into event-barrier-repr-multiprocessing
2 parents 57070f2 + f1c5363 commit 2675c93

428 files changed

Lines changed: 22252 additions & 8488 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/CODEOWNERS

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,14 @@
6363
.azure-pipelines/ @AA-Turner
6464

6565
# GitHub & related scripts
66-
.github/ @ezio-melotti @hugovk @AA-Turner @webknjaz @itamaro
66+
.github/ @ezio-melotti @hugovk @AA-Turner @webknjaz @itamaro @JacobCoffee
6767
Tools/build/compute-changes.py @AA-Turner @hugovk @webknjaz
6868
Lib/test/test_tools/test_compute_changes.py @AA-Turner @hugovk @webknjaz
6969
Tools/build/verify_ensurepip_wheels.py @AA-Turner @pfmoore @pradyunsg
7070

7171
# Pre-commit
72-
.pre-commit-config.yaml @hugovk
73-
.ruff.toml @hugovk @AlexWaygood @AA-Turner
72+
.pre-commit-config.yaml @hugovk @JacobCoffee
73+
.ruff.toml @hugovk @AlexWaygood @AA-Turner @JacobCoffee
7474

7575
# Patchcheck
7676
Tools/patchcheck/ @AA-Turner @itamaro

.github/workflows/build.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,9 @@ jobs:
601601
run: ./configure --prefix="$BUILD_DIR/cross-python" --with-build-python="$BUILD_DIR/host-python/bin/python3"
602602
- name: Install cross Python
603603
run: make -j8 install
604+
- name: Display build info
605+
run: |
606+
"$BUILD_DIR/cross-python/bin/python3" -m test.pythoninfo
604607
- name: Run test subset with host build
605608
run: |
606609
"$BUILD_DIR/cross-python/bin/python3" -m test test_sysconfig test_site test_embed

.github/workflows/jit.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ jobs:
6464
include:
6565
- target: i686-pc-windows-msvc/msvc
6666
architecture: Win32
67-
runner: windows-2025-vs2026
67+
runner: windows-2025
6868
- target: x86_64-pc-windows-msvc/msvc
6969
architecture: x64
70-
runner: windows-2025-vs2026
70+
runner: windows-2025
7171
- target: aarch64-pc-windows-msvc/msvc
7272
architecture: ARM64
7373
runner: windows-11-arm

.github/workflows/reusable-emscripten.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,17 @@ jobs:
6363
run: python3 Platforms/emscripten configure-build-python -- --config-cache --with-pydebug
6464
- name: "Make build Python"
6565
run: python3 Platforms/emscripten make-build-python
66+
- name: "Display build info of the build Python"
67+
run: python3 Platforms/emscripten pythoninfo-build
6668
- name: "Make dependencies"
6769
run: >-
6870
python3 Platforms/emscripten make-dependencies
6971
${{ steps.emsdk-cache.outputs.cache-hit == 'true' && '--check-up-to-date' || '' }}
70-
- name: "Configure host Python"
72+
- name: "Configure host/Emscripten Python"
7173
run: python3 Platforms/emscripten configure-host --host-runner node -- --config-cache
72-
- name: "Make host Python"
74+
- name: "Make host/Emscripten Python"
7375
run: python3 Platforms/emscripten make-host
74-
- name: "Display build info"
75-
run: python3 Platforms/emscripten run --pythoninfo
76+
- name: "Display build info of the host/Emscripten Python"
77+
run: python3 Platforms/emscripten pythoninfo-host
7678
- name: "Test"
7779
run: python3 Platforms/emscripten run --test

.github/workflows/reusable-wasi.yml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ jobs:
1616
timeout-minutes: 60
1717
env:
1818
WASMTIME_VERSION: 38.0.3
19-
CROSS_BUILD_PYTHON: cross-build/build
2019
CROSS_BUILD_WASI: cross-build/wasm32-wasip1
2120
steps:
2221
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -54,14 +53,16 @@ jobs:
5453
run: python3 Platforms/WASI configure-build-python -- --config-cache --with-pydebug
5554
- name: "Make build Python"
5655
run: python3 Platforms/WASI make-build-python
57-
- name: "Configure host"
56+
- name: "Display build info of the build Python"
57+
run: python3 Platforms/WASI pythoninfo-build
58+
- name: "Configure host/WASI Python"
5859
# `--with-pydebug` inferred from configure-build-python
5960
run: python3 Platforms/WASI configure-host -- --config-cache
6061
env:
6162
WASI_SDK_PATH: ${{ steps.install-wasi-sdk.outputs.wasi-sdk-path }}
62-
- name: "Make host"
63+
- name: "Make host/WASI Python"
6364
run: python3 Platforms/WASI make-host
64-
- name: "Display build info"
65-
run: make --directory "${CROSS_BUILD_WASI}" pythoninfo
65+
- name: "Display build info of the host/WASI Python"
66+
run: python3 Platforms/WASI pythoninfo-host
6667
- name: "Test"
6768
run: make --directory "${CROSS_BUILD_WASI}" test

.github/workflows/reusable-windows-msi.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ env:
1717
jobs:
1818
build:
1919
name: installer for ${{ inputs.arch }}
20-
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2025-vs2026' }}
20+
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2025' }}
2121
timeout-minutes: 60
2222
env:
2323
ARCH: ${{ inputs.arch }}

.github/workflows/reusable-windows.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ env:
2626
jobs:
2727
build:
2828
name: Build and test (${{ inputs.arch }}, ${{ inputs.interpreter }})
29-
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2025-vs2026' }}
29+
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2025' }}
3030
timeout-minutes: 60
3131
env:
3232
ARCH: ${{ inputs.arch }}

Doc/c-api/extension-modules.rst

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,35 @@ For example, a module called ``spam`` would be defined like this::
100100
The export hook is typically the only non-\ ``static``
101101
item defined in the module's C source.
102102

103-
The hook should be kept short -- ideally, one line as above.
104-
If you do need to use Python C API in this function, it is recommended to call
105-
``PyABIInfo_Check(&abi_info, "modulename")`` first to raise an exception,
106-
rather than crash, in common cases of ABI mismatch.
103+
.. _pymodexport-api-caveats:
107104

105+
The hook should be kept short.
106+
If it does more than ``return`` a static array, several caveats apply:
107+
108+
- If you need to use any Python C API, it is recommended to call
109+
:c:func:`PyABIInfo_Check` first to raise an exception,
110+
rather than crash, in common cases of ABI mismatch.
111+
- Code in the export hook must never rely on the :term:`GIL`:
112+
:term:`free-threaded builds <free-threaded build>` of Python can only check
113+
the :c:macro:`Py_mod_gil` slot (or the lack of it) after the hook returns,
114+
- Similarly, the hook may be called in any subinterpreter, since the
115+
:c:macro:`Py_mod_multiple_interpreters` slot (or lack of it)
116+
is only checked after the hook returns.
117+
118+
For example::
119+
120+
PyMODEXPORT_FUNC
121+
PyModExport_modulename(void)
122+
{
123+
if (PyABIInfo_Check(&abi_info, "modulename") < 0) {
124+
/* ABI mismatch. It's not safe to examine the raised exception. */
125+
return NULL;
126+
}
127+
128+
/* use Python API (as little as possible); don't rely on GIL */
129+
130+
return modulename_slots;
131+
}
108132

109133
.. note::
110134

Doc/c-api/import.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,11 @@ Importing Modules
304304
305305
Initialization function for a module built into the interpreter.
306306
307+
Note that the inittab uses "``PyInit``"
308+
:ref:`initialization functions <extension-pyinit>`;
309+
there is currently no way to include "``PyModExport_``"
310+
:ref:`export hooks <extension-export-hook>`.
311+
307312
308313
.. c:function:: int PyImport_ExtendInittab(struct _inittab *newtab)
309314

Doc/c-api/threads.rst

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,61 @@ a thread state that was previously attached for the current thread.
242242
.. seealso::
243243
:pep:`788`
244244

245+
.. _c-api-reuse-thread-state:
246+
247+
Reusing a thread state across repeated calls
248+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
249+
250+
Creating and destroying a :c:type:`PyThreadState` is not free, and is more
251+
expensive on a :term:`free-threaded build`. A foreign thread that calls into
252+
the interpreter many times -- for example, a worker thread in a native thread
253+
pool -- should avoid creating a fresh thread state on every entry and
254+
destroying it on every exit. Instead, set up one thread state when the thread
255+
starts (or lazily on its first call into Python), attach and detach it around
256+
each call, and tear it down once when the thread exits.
257+
258+
Manage the thread state explicitly with :c:func:`PyThreadState_New`, attaching
259+
and detaching it with :c:func:`PyEval_RestoreThread` and
260+
:c:func:`PyEval_SaveThread`. This happens in three distinct phases, at
261+
different points in the thread's life.
262+
263+
When the thread starts, create one thread state for it. ``interp`` is the
264+
target interpreter, captured by the code that created this thread while it held
265+
an attached thread state (for example via :c:func:`PyInterpreterState_Get`)::
266+
267+
PyThreadState *tstate = PyThreadState_New(interp);
268+
269+
Then, on each call into Python -- which may happen many times over the thread's
270+
life -- attach the thread state, make the Python C API calls that require it,
271+
and detach again so the thread does not hold the GIL while off doing non-Python
272+
work::
273+
274+
PyEval_RestoreThread(tstate);
275+
result = CallSomeFunction(); /* your Python C API calls go here */
276+
PyEval_SaveThread();
277+
278+
When the thread is finished calling into Python, destroy the thread state once::
279+
280+
PyEval_RestoreThread(tstate);
281+
PyThreadState_Clear(tstate);
282+
PyThreadState_DeleteCurrent();
283+
284+
The general-purpose entry points for calling in from a foreign thread --
285+
:c:func:`PyThreadState_Ensure` and the older :c:func:`PyGILState_Ensure` -- do
286+
*not* guarantee a persistent thread state: their thread-state lifetime is
287+
deliberately implementation-defined, so a matched acquire/release pair may
288+
create and destroy a thread state each time. Use :c:func:`PyThreadState_New`,
289+
as shown here, whenever you specifically want to reuse one thread state across
290+
calls.
291+
292+
The code that created the foreign thread must arrange for the shutdown sequence
293+
to run before the thread exits, and before :c:func:`Py_FinalizeEx` is called.
294+
If interpreter finalization begins first, the shutdown
295+
:c:func:`PyEval_RestoreThread` call will hang the thread rather than return (see
296+
:ref:`cautions-regarding-runtime-finalization`). If the thread exits without
297+
running the shutdown sequence, the thread state is leaked for the remainder of
298+
the process.
299+
245300
.. _c-api-attach-detach:
246301

247302
Attaching/detaching thread states

0 commit comments

Comments
 (0)