Skip to content

Commit f8f4e63

Browse files
authored
Merge branch 'main' into use-importlib-resources-for-doctest
2 parents 2472168 + ae47888 commit f8f4e63

File tree

305 files changed

+7518
-4763
lines changed

Some content is hidden

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

305 files changed

+7518
-4763
lines changed

.github/workflows/build.yml

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -512,26 +512,59 @@ jobs:
512512
run: xvfb-run make ci
513513

514514
build_tsan:
515-
name: 'Thread sanitizer'
515+
name: >-
516+
Thread sanitizer
517+
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
516518
needs: check_source
517519
if: needs.check_source.outputs.run_tests == 'true'
520+
strategy:
521+
matrix:
522+
free-threading:
523+
- false
524+
- true
518525
uses: ./.github/workflows/reusable-tsan.yml
519526
with:
520527
config_hash: ${{ needs.check_source.outputs.config_hash }}
521-
options: ./configure --config-cache --with-thread-sanitizer --with-pydebug
522-
suppressions_path: Tools/tsan/supressions.txt
523-
tsan_logs_artifact_name: tsan-logs-default
528+
free-threading: ${{ matrix.free-threading }}
524529

525-
build_tsan_free_threading:
526-
name: 'Thread sanitizer (free-threading)'
530+
cross-build-linux:
531+
name: Cross build Linux
532+
runs-on: ubuntu-latest
527533
needs: check_source
528534
if: needs.check_source.outputs.run_tests == 'true'
529-
uses: ./.github/workflows/reusable-tsan.yml
530-
with:
531-
config_hash: ${{ needs.check_source.outputs.config_hash }}
532-
options: ./configure --config-cache --disable-gil --with-thread-sanitizer --with-pydebug
533-
suppressions_path: Tools/tsan/suppressions_free_threading.txt
534-
tsan_logs_artifact_name: tsan-logs-free-threading
535+
steps:
536+
- uses: actions/checkout@v4
537+
with:
538+
persist-credentials: false
539+
- name: Runner image version
540+
run: echo "IMAGE_VERSION=${ImageVersion}" >> "$GITHUB_ENV"
541+
- name: Restore config.cache
542+
uses: actions/cache@v4
543+
with:
544+
path: config.cache
545+
key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.outputs.config_hash }}
546+
- name: Register gcc problem matcher
547+
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
548+
- name: Set build dir
549+
run:
550+
# an absolute path outside of the working directoy
551+
echo "BUILD_DIR=$(realpath ${{ github.workspace }}/../build)" >> "$GITHUB_ENV"
552+
- name: Install Dependencies
553+
run: sudo ./.github/workflows/posix-deps-apt.sh
554+
- name: Configure host build
555+
run: ./configure --prefix="$BUILD_DIR/host-python"
556+
- name: Install host Python
557+
run: make -j8 install
558+
- name: Run test subset with host build
559+
run: |
560+
"$BUILD_DIR/host-python/bin/python3" -m test test_sysconfig test_site test_embed
561+
- name: Configure cross build
562+
run: ./configure --prefix="$BUILD_DIR/cross-python" --with-build-python="$BUILD_DIR/host-python/bin/python3"
563+
- name: Install cross Python
564+
run: make -j8 install
565+
- name: Run test subset with host build
566+
run: |
567+
"$BUILD_DIR/cross-python/bin/python3" -m test test_sysconfig test_site test_embed
535568
536569
# CIFuzz job based on https://google.github.io/oss-fuzz/getting-started/continuous-integration/
537570
cifuzz:
@@ -591,7 +624,6 @@ jobs:
591624
- test_hypothesis
592625
- build_asan
593626
- build_tsan
594-
- build_tsan_free_threading
595627
- cifuzz
596628

597629
runs-on: ubuntu-latest
@@ -625,7 +657,6 @@ jobs:
625657
build_windows,
626658
build_asan,
627659
build_tsan,
628-
build_tsan_free_threading,
629660
'
630661
|| ''
631662
}}

.github/workflows/reusable-tsan.yml

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,11 @@ on:
66
config_hash:
77
required: true
88
type: string
9-
options:
10-
required: true
11-
type: string
12-
suppressions_path:
13-
description: 'A repo relative path to the suppressions file'
14-
required: true
15-
type: string
16-
tsan_logs_artifact_name:
17-
description: 'Name of the TSAN logs artifact. Must be unique for each job.'
18-
required: true
19-
type: string
9+
free-threading:
10+
description: Whether to use free-threaded mode
11+
required: false
12+
type: boolean
13+
default: false
2014

2115
env:
2216
FORCE_COLOR: 1
@@ -26,9 +20,6 @@ jobs:
2620
name: 'Thread sanitizer'
2721
runs-on: ubuntu-24.04
2822
timeout-minutes: 60
29-
env:
30-
OPTIONS: ${{ inputs.options }}
31-
SUPPRESSIONS_PATH: ${{ inputs.suppressions_path }}
3223
steps:
3324
- uses: actions/checkout@v4
3425
with:
@@ -55,7 +46,11 @@ jobs:
5546
sudo sysctl -w vm.mmap_rnd_bits=28
5647
- name: TSAN Option Setup
5748
run: |
58-
echo "TSAN_OPTIONS=log_path=${GITHUB_WORKSPACE}/tsan_log suppressions=${GITHUB_WORKSPACE}/${SUPPRESSIONS_PATH} handle_segv=0" >> "$GITHUB_ENV"
49+
echo "TSAN_OPTIONS=log_path=${GITHUB_WORKSPACE}/tsan_log suppressions=${GITHUB_WORKSPACE}/Tools/tsan/suppressions${{
50+
fromJSON(inputs.free-threading)
51+
&& '_free_threading'
52+
|| ''
53+
}}.txt handle_segv=0" >> "$GITHUB_ENV"
5954
echo "CC=clang" >> "$GITHUB_ENV"
6055
echo "CXX=clang++" >> "$GITHUB_ENV"
6156
- name: Add ccache to PATH
@@ -67,7 +62,12 @@ jobs:
6762
save: ${{ github.event_name == 'push' }}
6863
max-size: "200M"
6964
- name: Configure CPython
70-
run: "${OPTIONS}"
65+
run: >-
66+
./configure
67+
--config-cache
68+
--with-thread-sanitizer
69+
--with-pydebug
70+
${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
7171
- name: Build CPython
7272
run: make -j4
7373
- name: Display build info
@@ -81,6 +81,11 @@ jobs:
8181
if: always()
8282
uses: actions/upload-artifact@v4
8383
with:
84-
name: ${{ inputs.tsan_logs_artifact_name }}
84+
name: >-
85+
tsan-logs-${{
86+
fromJSON(inputs.free-threading)
87+
&& 'free-threading'
88+
|| 'default'
89+
}}
8590
path: tsan_log.*
8691
if-no-files-found: ignore

.github/workflows/reusable-windows.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ env:
2424
2525
jobs:
2626
build:
27-
name: 'build and test (${{ inputs.arch }})'
27+
name: ${{ inputs.arch == 'arm64' && 'build' || 'build and test' }} (${{ inputs.arch }})
2828
runs-on: ${{ inputs.os }}
2929
timeout-minutes: 60
3030
env:

Android/android-env.sh

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# This script must be sourced with the following variables already set:
2-
: ${ANDROID_HOME:?} # Path to Android SDK
3-
: ${HOST:?} # GNU target triplet
2+
: "${ANDROID_HOME:?}" # Path to Android SDK
3+
: "${HOST:?}" # GNU target triplet
44

55
# You may also override the following:
6-
: ${api_level:=24} # Minimum Android API level the build will run on
7-
: ${PREFIX:-} # Path in which to find required libraries
6+
: "${api_level:=24}" # Minimum Android API level the build will run on
7+
: "${PREFIX:-}" # Path in which to find required libraries
88

99

1010
# Print all messages on stderr so they're visible when running within build-wheel.
@@ -27,20 +27,20 @@ fail() {
2727
ndk_version=27.1.12297006
2828

2929
ndk=$ANDROID_HOME/ndk/$ndk_version
30-
if ! [ -e $ndk ]; then
30+
if ! [ -e "$ndk" ]; then
3131
log "Installing NDK - this may take several minutes"
32-
yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "ndk;$ndk_version"
32+
yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "ndk;$ndk_version"
3333
fi
3434

35-
if [ $HOST = "arm-linux-androideabi" ]; then
35+
if [ "$HOST" = "arm-linux-androideabi" ]; then
3636
clang_triplet=armv7a-linux-androideabi
3737
else
38-
clang_triplet=$HOST
38+
clang_triplet="$HOST"
3939
fi
4040

4141
# These variables are based on BuildSystemMaintainers.md above, and
4242
# $ndk/build/cmake/android.toolchain.cmake.
43-
toolchain=$(echo $ndk/toolchains/llvm/prebuilt/*)
43+
toolchain=$(echo "$ndk"/toolchains/llvm/prebuilt/*)
4444
export AR="$toolchain/bin/llvm-ar"
4545
export AS="$toolchain/bin/llvm-as"
4646
export CC="$toolchain/bin/${clang_triplet}${api_level}-clang"
@@ -72,12 +72,12 @@ LDFLAGS="$LDFLAGS -lm"
7272

7373
# -mstackrealign is included where necessary in the clang launcher scripts which are
7474
# pointed to by $CC, so we don't need to include it here.
75-
if [ $HOST = "arm-linux-androideabi" ]; then
75+
if [ "$HOST" = "arm-linux-androideabi" ]; then
7676
CFLAGS="$CFLAGS -march=armv7-a -mthumb"
7777
fi
7878

7979
if [ -n "${PREFIX:-}" ]; then
80-
abs_prefix=$(realpath $PREFIX)
80+
abs_prefix="$(realpath "$PREFIX")"
8181
CFLAGS="$CFLAGS -I$abs_prefix/include"
8282
LDFLAGS="$LDFLAGS -L$abs_prefix/lib"
8383

@@ -87,11 +87,13 @@ fi
8787

8888
# When compiling C++, some build systems will combine CFLAGS and CXXFLAGS, and some will
8989
# use CXXFLAGS alone.
90-
export CXXFLAGS=$CFLAGS
90+
export CXXFLAGS="$CFLAGS"
9191

9292
# Use the same variable name as conda-build
93-
if [ $(uname) = "Darwin" ]; then
94-
export CPU_COUNT=$(sysctl -n hw.ncpu)
93+
if [ "$(uname)" = "Darwin" ]; then
94+
CPU_COUNT="$(sysctl -n hw.ncpu)"
95+
export CPU_COUNT
9596
else
96-
export CPU_COUNT=$(nproc)
97+
CPU_COUNT="$(nproc)"
98+
export CPU_COUNT
9799
fi

Doc/c-api/import.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,3 +325,24 @@ Importing Modules
325325
If Python is initialized multiple times, :c:func:`PyImport_AppendInittab` or
326326
:c:func:`PyImport_ExtendInittab` must be called before each Python
327327
initialization.
328+
329+
330+
.. c:function:: PyObject* PyImport_ImportModuleAttr(PyObject *mod_name, PyObject *attr_name)
331+
332+
Import the module *mod_name* and get its attribute *attr_name*.
333+
334+
Names must be Python :class:`str` objects.
335+
336+
Helper function combining :c:func:`PyImport_Import` and
337+
:c:func:`PyObject_GetAttr`. For example, it can raise :exc:`ImportError` if
338+
the module is not found, and :exc:`AttributeError` if the attribute doesn't
339+
exist.
340+
341+
.. versionadded:: 3.14
342+
343+
.. c:function:: PyObject* PyImport_ImportModuleAttrString(const char *mod_name, const char *attr_name)
344+
345+
Similar to :c:func:`PyImport_ImportModuleAttr`, but names are UTF-8 encoded
346+
strings instead of Python :class:`str` objects.
347+
348+
.. versionadded:: 3.14

Doc/c-api/long.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,6 @@ The :c:type:`PyLongWriter` API can be used to import an integer.
824824
825825
Discard a :c:type:`PyLongWriter` created by :c:func:`PyLongWriter_Create`.
826826
827-
*writer* must not be ``NULL``.
827+
If *writer* is ``NULL``, no operation is performed.
828828
829829
The writer instance and the *digits* array are invalid after the call.

Doc/c-api/object.rst

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,3 +613,95 @@ Object Protocol
613613
614614
.. versionadded:: 3.14
615615
616+
.. c:function:: int PyUnstable_IsImmortal(PyObject *obj)
617+
618+
This function returns non-zero if *obj* is :term:`immortal`, and zero
619+
otherwise. This function cannot fail.
620+
621+
.. note::
622+
623+
Objects that are immortal in one CPython version are not guaranteed to
624+
be immortal in another.
625+
626+
.. versionadded:: next
627+
628+
.. c:function:: int PyUnstable_TryIncRef(PyObject *obj)
629+
630+
Increments the reference count of *obj* if it is not zero. Returns ``1``
631+
if the object's reference count was successfully incremented. Otherwise,
632+
this function returns ``0``.
633+
634+
:c:func:`PyUnstable_EnableTryIncRef` must have been called
635+
earlier on *obj* or this function may spuriously return ``0`` in the
636+
:term:`free threading` build.
637+
638+
This function is logically equivalent to the following C code, except that
639+
it behaves atomically in the :term:`free threading` build::
640+
641+
if (Py_REFCNT(op) > 0) {
642+
Py_INCREF(op);
643+
return 1;
644+
}
645+
return 0;
646+
647+
This is intended as a building block for managing weak references
648+
without the overhead of a Python :ref:`weak reference object <weakrefobjects>`.
649+
650+
Typically, correct use of this function requires support from *obj*'s
651+
deallocator (:c:member:`~PyTypeObject.tp_dealloc`).
652+
For example, the following sketch could be adapted to implement a
653+
"weakmap" that works like a :py:class:`~weakref.WeakValueDictionary`
654+
for a specific type:
655+
656+
.. code-block:: c
657+
658+
PyMutex mutex;
659+
660+
PyObject *
661+
add_entry(weakmap_key_type *key, PyObject *value)
662+
{
663+
PyUnstable_EnableTryIncRef(value);
664+
weakmap_type weakmap = ...;
665+
PyMutex_Lock(&mutex);
666+
weakmap_add_entry(weakmap, key, value);
667+
PyMutex_Unlock(&mutex);
668+
Py_RETURN_NONE;
669+
}
670+
671+
PyObject *
672+
get_value(weakmap_key_type *key)
673+
{
674+
weakmap_type weakmap = ...;
675+
PyMutex_Lock(&mutex);
676+
PyObject *result = weakmap_find(weakmap, key);
677+
if (PyUnstable_TryIncRef(result)) {
678+
// `result` is safe to use
679+
PyMutex_Unlock(&mutex);
680+
return result;
681+
}
682+
// if we get here, `result` is starting to be garbage-collected,
683+
// but has not been removed from the weakmap yet
684+
PyMutex_Unlock(&mutex);
685+
return NULL;
686+
}
687+
688+
// tp_dealloc function for weakmap values
689+
void
690+
value_dealloc(PyObject *value)
691+
{
692+
weakmap_type weakmap = ...;
693+
PyMutex_Lock(&mutex);
694+
weakmap_remove_value(weakmap, value);
695+
696+
...
697+
PyMutex_Unlock(&mutex);
698+
}
699+
700+
.. versionadded:: 3.14
701+
702+
.. c:function:: void PyUnstable_EnableTryIncRef(PyObject *obj)
703+
704+
Enables subsequent uses of :c:func:`PyUnstable_TryIncRef` on *obj*. The
705+
caller must hold a :term:`strong reference` to *obj* when calling this.
706+
707+
.. versionadded:: 3.14

Doc/conf.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
'changes',
2929
'glossary_search',
3030
'lexers',
31+
'misc_news',
3132
'pydoc_topics',
3233
'pyspecific',
3334
'sphinx.ext.coverage',
@@ -560,8 +561,6 @@
560561
r'https://github.com/python/cpython/tree/.*': 'https://github.com/python/cpython/blob/.*',
561562
# Intentional HTTP use at Misc/NEWS.d/3.5.0a1.rst
562563
r'http://www.python.org/$': 'https://www.python.org/$',
563-
# Used in license page, keep as is
564-
r'https://www.zope.org/': r'https://www.zope.dev/',
565564
# Microsoft's redirects to learn.microsoft.com
566565
r'https://msdn.microsoft.com/.*': 'https://learn.microsoft.com/.*',
567566
r'https://docs.microsoft.com/.*': 'https://learn.microsoft.com/.*',

0 commit comments

Comments
 (0)