diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml
index 7490dd947e1504..9b3415fd2b5861 100644
--- a/.azure-pipelines/ci.yml
+++ b/.azure-pipelines/ci.yml
@@ -1,4 +1,4 @@
-trigger: ['main', '3.13', '3.12', '3.11', '3.10', '3.9', '3.8']
+trigger: ['main', '3.*']
jobs:
- job: Prebuild
diff --git a/.editorconfig b/.editorconfig
index a6187d64f3ce46..5b04b32a89e3d2 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,6 +1,6 @@
root = true
-[*.{py,c,cpp,h,js,rst,md,yml}]
+[*.{py,c,cpp,h,js,rst,md,yml,yaml}]
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
@@ -11,5 +11,5 @@ indent_size = 4
[*.rst]
indent_size = 3
-[*.{js,yml}]
+[*.{js,yml,yaml}]
indent_size = 2
diff --git a/.gitattributes b/.gitattributes
index 2f5a030981fb94..5682b9150a36e2 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -10,6 +10,7 @@
*.ico binary
*.jpg binary
*.pck binary
+*.pdf binary
*.png binary
*.psd binary
*.tar binary
@@ -67,6 +68,7 @@ PCbuild/readme.txt dos
**/clinic/*.cpp.h generated
**/clinic/*.h.h generated
*_db.h generated
+Doc/c-api/lifecycle.dot.svg generated
Doc/data/stable_abi.dat generated
Doc/library/token-list.inc generated
Include/internal/pycore_ast.h generated
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 2fc9c772fa7757..88b957669826f7 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -30,6 +30,7 @@ Modules/Setup* @erlend-aasland
Objects/set* @rhettinger
Objects/dict* @methane @markshannon
Objects/typevarobject.c @JelleZijlstra
+Objects/unionobject.c @JelleZijlstra
Objects/type* @markshannon
Objects/codeobject.c @markshannon
Objects/frameobject.c @markshannon
@@ -107,13 +108,16 @@ Objects/exceptions.c @iritkatriel
# Hashing & cryptographic primitives
**/*hashlib* @gpshead @tiran @picnixz
**/*hashopenssl* @gpshead @tiran @picnixz
-**/*pyhash* @gpshead @tiran
-**/sha* @gpshead @tiran @picnixz
-Modules/md5* @gpshead @tiran @picnixz
-**/*blake* @gpshead @tiran @picnixz
-Modules/_hacl/** @gpshead
+**/*pyhash* @gpshead @tiran @picnixz
+Modules/*blake* @gpshead @tiran @picnixz
+Modules/*md5* @gpshead @tiran @picnixz
+Modules/*sha* @gpshead @tiran @picnixz
+Modules/_hacl/** @gpshead @picnixz
**/*hmac* @gpshead @picnixz
+# libssl
+**/*ssl* @gpshead @picnixz
+
# logging
**/*logging* @vsajip
@@ -164,6 +168,9 @@ Include/internal/pycore_time.h @pganssle @abalkin
**/*imap* @python/email-team
**/*poplib* @python/email-team
+# Exclude .mailmap from being owned by @python/email-team
+/.mailmap
+
# Garbage collector
/Modules/gcmodule.c @pablogsal
/Doc/library/gc.rst @pablogsal
@@ -181,10 +188,11 @@ Include/internal/pycore_time.h @pganssle @abalkin
# AST
Python/ast.c @isidentical @JelleZijlstra @eclips4
-Python/ast_opt.c @isidentical @eclips4
+Python/ast_preprocess.c @isidentical @eclips4
Parser/asdl.py @isidentical @JelleZijlstra @eclips4
Parser/asdl_c.py @isidentical @JelleZijlstra @eclips4
Lib/ast.py @isidentical @JelleZijlstra @eclips4
+Lib/_ast_unparse.py @isidentical @JelleZijlstra @eclips4
Lib/test/test_ast/ @eclips4
# Mock
@@ -290,7 +298,12 @@ Lib/test/test_interpreters/ @ericsnowcurrently
**/*-ios* @freakboy3742
# WebAssembly
-/Tools/wasm/ @brettcannon @freakboy3742
+Tools/wasm/config.site-wasm32-emscripten @freakboy3742
+/Tools/wasm/README.md @brettcannon @freakboy3742
+/Tools/wasm/wasi-env @brettcannon
+/Tools/wasm/wasi.py @brettcannon
+/Tools/wasm/emscripten @freakboy3742
+/Tools/wasm/wasi @brettcannon
# SBOM
/Misc/externals.spdx.json @sethmlarson
@@ -309,3 +322,12 @@ Doc/reference/ @willingc @AA-Turner
# Colorize
Lib/_colorize.py @hugovk
Lib/test/test__colorize.py @hugovk
+
+# Fuzzing
+Modules/_xxtestfuzz/ @ammaraskar
+
+# t-strings
+**/*interpolationobject* @lysnikolaou
+**/*templateobject* @lysnikolaou
+**/*templatelib* @lysnikolaou
+**/*tstring* @lysnikolaou
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
index 7b7810cf6965fd..da70710b7ecfa3 100644
--- a/.github/ISSUE_TEMPLATE/bug.yml
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -40,6 +40,7 @@ body:
- "3.12"
- "3.13"
- "3.14"
+ - "3.15"
- "CPython main branch"
validations:
required: true
diff --git a/.github/ISSUE_TEMPLATE/crash.yml b/.github/ISSUE_TEMPLATE/crash.yml
index 58da2dfe0c7354..470ad581367b10 100644
--- a/.github/ISSUE_TEMPLATE/crash.yml
+++ b/.github/ISSUE_TEMPLATE/crash.yml
@@ -33,6 +33,7 @@ body:
- "3.12"
- "3.13"
- "3.14"
+ - "3.15"
- "CPython main branch"
validations:
required: true
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 4cc2f461dbe2f2..03ea959ca14e28 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -7,10 +7,10 @@ Please read this comment in its entirety. It's quite important.
It should be in the following format:
```
-gh-NNNNN: Summary of the changes made
+gh-NNNNNN: Summary of the changes made
```
-Where: gh-NNNNN refers to the GitHub issue number.
+Where: gh-NNNNNN refers to the GitHub issue number.
Most PRs will require an issue number. Trivial changes, like fixing a typo, do not need an issue.
@@ -20,11 +20,11 @@ If this is a backport PR (PR made against branches other than `main`),
please ensure that the PR title is in the following format:
```
-[X.Y]
(GH-NNNN)
+[X.Y] (GH-NNNNNN)
```
-Where: [X.Y] is the branch name, e.g. [3.6].
+Where: [X.Y] is the branch name, for example: [3.13].
-GH-NNNN refers to the PR number from `main`.
+GH-NNNNNN refers to the PR number from `main`.
-->
diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml
index af125266ae7813..68aae196357414 100644
--- a/.github/actionlint.yaml
+++ b/.github/actionlint.yaml
@@ -1,5 +1,6 @@
self-hosted-runner:
- labels: ["windows-aarch64"]
+ # Pending https://github.com/rhysd/actionlint/issues/533
+ labels: ["windows-11-arm"]
config-variables: null
diff --git a/.github/workflows/add-issue-header.yml b/.github/workflows/add-issue-header.yml
index 570b8779994a0f..3cbc23af578d10 100644
--- a/.github/workflows/add-issue-header.yml
+++ b/.github/workflows/add-issue-header.yml
@@ -18,6 +18,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
issues: write
+ timeout-minutes: 5
steps:
- uses: actions/github-script@v7
with:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e94c483c9ae9dc..b192508c78685c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -43,7 +43,7 @@ jobs:
if: fromJSON(needs.build-context.outputs.run-docs)
uses: ./.github/workflows/reusable-docs.yml
- check_autoconf_regen:
+ check-autoconf-regen:
name: 'Check if Autoconf files are up to date'
# Don't use ubuntu-latest but a specific version to make the job
# reproducible: to get the same tools versions (autoconf, aclocal, ...)
@@ -86,7 +86,7 @@ jobs:
exit 1
fi
- check_generated_files:
+ check-generated-files:
name: 'Check if generated files are up to date'
# Don't use ubuntu-latest but a specific version to make the job
# reproducible: to get the same tools versions (autoconf, aclocal, ...)
@@ -147,7 +147,7 @@ jobs:
if: github.event_name == 'pull_request' # $GITHUB_EVENT_NAME
run: make check-c-globals
- build_windows:
+ build-windows:
name: >-
Windows
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
@@ -156,35 +156,28 @@ jobs:
strategy:
fail-fast: false
matrix:
- os:
- - windows-latest
arch:
- x64
+ - Win32
+ - arm64
free-threading:
- false
- true
- include:
- - os: windows-latest # FIXME(diegorusso): change to os: windows-aarch64
- arch: arm64
- free-threading: false
- - os: windows-latest # FIXME(diegorusso): change to os: windows-aarch64
- arch: arm64
- free-threading: true
- - os: windows-latest
- arch: Win32
- free-threading: false
+ exclude:
+ # Skip Win32 on free-threaded builds
+ - { arch: Win32, free-threading: true }
uses: ./.github/workflows/reusable-windows.yml
with:
- os: ${{ matrix.os }}
arch: ${{ matrix.arch }}
free-threading: ${{ matrix.free-threading }}
- build_windows_msi:
+ build-windows-msi:
name: >- # ${{ '' } is a hack to nest jobs under the same sidebar category
Windows MSI${{ '' }}
needs: build-context
if: fromJSON(needs.build-context.outputs.run-windows-msi)
strategy:
+ fail-fast: false
matrix:
arch:
- x86
@@ -194,7 +187,7 @@ jobs:
with:
arch: ${{ matrix.arch }}
- build_macos:
+ build-macos:
name: >-
macOS
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
@@ -228,7 +221,7 @@ jobs:
free-threading: ${{ matrix.free-threading }}
os: ${{ matrix.os }}
- build_ubuntu:
+ build-ubuntu:
name: >-
Ubuntu
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
@@ -236,6 +229,7 @@ jobs:
needs: build-context
if: needs.build-context.outputs.run-tests == 'true'
strategy:
+ fail-fast: false
matrix:
bolt:
- false
@@ -260,7 +254,7 @@ jobs:
free-threading: ${{ matrix.free-threading }}
os: ${{ matrix.os }}
- build_ubuntu_ssltests:
+ build-ubuntu-ssltests:
name: 'Ubuntu SSL tests with OpenSSL'
runs-on: ${{ matrix.os }}
timeout-minutes: 60
@@ -270,7 +264,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-24.04]
- openssl_ver: [3.0.15, 3.1.7, 3.2.3, 3.3.2, 3.4.0]
+ openssl_ver: [3.0.16, 3.1.8, 3.2.4, 3.3.3, 3.4.1]
# See Tools/ssl/make_ssl_data.py for notes on adding a new version
env:
OPENSSL_VER: ${{ matrix.openssl_ver }}
@@ -322,7 +316,7 @@ jobs:
- name: SSL tests
run: ./python Lib/test/ssltests.py
- build_wasi:
+ build-wasi:
name: 'WASI'
needs: build-context
if: needs.build-context.outputs.run-tests == 'true'
@@ -330,14 +324,14 @@ jobs:
with:
config_hash: ${{ needs.build-context.outputs.config-hash }}
- test_hypothesis:
+ test-hypothesis:
name: "Hypothesis tests on Ubuntu"
runs-on: ubuntu-24.04
timeout-minutes: 60
needs: build-context
if: needs.build-context.outputs.run-tests == 'true'
env:
- OPENSSL_VER: 3.0.15
+ OPENSSL_VER: 3.0.16
PYTHONSTRICTEXTENSIONBUILD: 1
steps:
- uses: actions/checkout@v4
@@ -428,8 +422,9 @@ jobs:
# failing when executed from inside a virtual environment.
"${VENV_PYTHON}" -m test \
-W \
- -o \
+ --slowest \
-j4 \
+ --timeout 900 \
-x test_asyncio \
-x test_multiprocessing_fork \
-x test_multiprocessing_forkserver \
@@ -445,18 +440,18 @@ jobs:
name: hypothesis-example-db
path: ${{ env.CPYTHON_BUILDDIR }}/.hypothesis/examples/
-
- build_asan:
+ build-asan:
name: 'Address sanitizer'
runs-on: ${{ matrix.os }}
timeout-minutes: 60
needs: build-context
if: needs.build-context.outputs.run-tests == 'true'
strategy:
+ fail-fast: false
matrix:
os: [ubuntu-24.04]
env:
- OPENSSL_VER: 3.0.15
+ OPENSSL_VER: 3.0.16
PYTHONSTRICTEXTENSIONBUILD: 1
ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
steps:
@@ -509,13 +504,14 @@ jobs:
- name: Tests
run: xvfb-run make ci
- build_tsan:
+ build-tsan:
name: >-
Thread sanitizer
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
needs: build-context
if: needs.build-context.outputs.run-tests == 'true'
strategy:
+ fail-fast: false
matrix:
free-threading:
- false
@@ -528,6 +524,7 @@ jobs:
cross-build-linux:
name: Cross build Linux
runs-on: ubuntu-latest
+ timeout-minutes: 60
needs: build-context
if: needs.build-context.outputs.run-tests == 'true'
steps:
@@ -592,8 +589,8 @@ jobs:
output-sarif: true
sanitizer: ${{ matrix.sanitizer }}
- name: Upload crash
- uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success'
+ uses: actions/upload-artifact@v4
with:
name: ${{ matrix.sanitizer }}-artifacts
path: ./out/artifacts
@@ -606,36 +603,35 @@ jobs:
all-required-green: # This job does nothing and is only used for the branch protection
name: All required checks pass
- if: always()
-
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
needs:
- build-context # Transitive dependency, needed to access `run-tests` value
- check-docs
- - check_autoconf_regen
- - check_generated_files
- - build_macos
- - build_ubuntu
- - build_ubuntu_ssltests
- - build_wasi
- - build_windows
- - build_windows_msi
+ - check-autoconf-regen
+ - check-generated-files
+ - build-windows
+ - build-windows-msi
+ - build-macos
+ - build-ubuntu
+ - build-ubuntu-ssltests
+ - build-wasi
+ - test-hypothesis
+ - build-asan
+ - build-tsan
- cross-build-linux
- - test_hypothesis
- - build_asan
- - build_tsan
- cifuzz
-
- runs-on: ubuntu-latest
+ if: always()
steps:
- name: Check whether the needed jobs succeeded or failed
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe
with:
allowed-failures: >-
- build_ubuntu_ssltests,
- build_windows_msi,
+ build-windows-msi,
+ build-ubuntu-ssltests,
+ test-hypothesis,
cifuzz,
- test_hypothesis,
allowed-skips: >-
${{
!fromJSON(needs.build-context.outputs.run-docs)
@@ -647,15 +643,15 @@ jobs:
${{
needs.build-context.outputs.run-tests != 'true'
&& '
- check_autoconf_regen,
- check_generated_files,
- build_macos,
- build_ubuntu,
- build_ubuntu_ssltests,
- build_wasi,
- build_asan,
- build_tsan,
- test_hypothesis,
+ check-autoconf-regen,
+ check-generated-files,
+ build-macos,
+ build-ubuntu,
+ build-ubuntu-ssltests,
+ build-wasi,
+ test-hypothesis,
+ build-asan,
+ build-tsan,
cross-build-linux,
'
|| ''
@@ -663,7 +659,7 @@ jobs:
${{
!fromJSON(needs.build-context.outputs.run-windows-tests)
&& '
- build_windows,
+ build-windows,
'
|| ''
}}
diff --git a/.github/workflows/documentation-links.yml b/.github/workflows/documentation-links.yml
index fdb4b9aa29a7c8..a09a30587b35eb 100644
--- a/.github/workflows/documentation-links.yml
+++ b/.github/workflows/documentation-links.yml
@@ -19,6 +19,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
pull-requests: write
+ timeout-minutes: 5
steps:
- uses: readthedocs/actions/preview@v1
diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml
index 806a8524112d76..116e0c1e945e38 100644
--- a/.github/workflows/jit.yml
+++ b/.github/workflows/jit.yml
@@ -74,7 +74,7 @@ jobs:
runner: windows-latest
- target: aarch64-pc-windows-msvc/msvc
architecture: ARM64
- runner: windows-latest
+ runner: windows-11-arm
- target: x86_64-apple-darwin/clang
architecture: x86_64
runner: macos-13
@@ -95,36 +95,29 @@ jobs:
with:
python-version: '3.11'
- - name: Native Windows
- if: runner.os == 'Windows' && matrix.architecture != 'ARM64'
+ # PCbuild downloads LLVM automatically:
+ - name: Windows
+ if: runner.os == 'Windows'
run: |
- choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }}
./PCbuild/rt.bat ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
- # No tests (yet):
- - name: Emulated Windows
- if: runner.os == 'Windows' && matrix.architecture == 'ARM64'
- run: |
- choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
- ./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }}
-
# The `find` line is required as a result of https://github.com/actions/runner-images/issues/9966.
# This is a bug in the macOS runner image where the pre-installed Python is installed in the same
# directory as the Homebrew Python, which causes the build to fail for macos-13. This line removes
# the symlink to the pre-installed Python so that the Homebrew Python is used instead.
- - name: Native macOS
+ - name: macOS
if: runner.os == 'macOS'
run: |
brew update
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
brew install llvm@${{ matrix.llvm }}
export SDKROOT="$(xcrun --show-sdk-path)"
- ./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '' }}
+ ./configure --enable-experimental-jit --enable-universalsdk --with-universal-archs=universal2 ${{ matrix.debug && '--with-pydebug' || '' }}
make all --jobs 4
./python.exe -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
- - name: Native Linux
+ - name: Linux
if: runner.os == 'Linux'
run: |
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
@@ -133,27 +126,30 @@ jobs:
make all --jobs 4
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
- jit-with-disabled-gil:
- name: Free-Threaded (Debug)
- needs: interpreter
- runs-on: ubuntu-24.04
- strategy:
- matrix:
- llvm:
- - 19
- steps:
- - uses: actions/checkout@v4
- with:
- persist-credentials: false
- - uses: actions/setup-python@v5
- with:
- python-version: '3.11'
- - name: Build with JIT enabled and GIL disabled
- run: |
- sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
- export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH"
- ./configure --enable-experimental-jit --with-pydebug --disable-gil
- make all --jobs 4
- - name: Run tests
- run: |
- ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
+ # XXX: GH-133171
+ # jit-with-disabled-gil:
+ # name: Free-Threaded (Debug)
+ # needs: interpreter
+ # runs-on: ubuntu-24.04
+ # timeout-minutes: 90
+ # strategy:
+ # fail-fast: false
+ # matrix:
+ # llvm:
+ # - 19
+ # steps:
+ # - uses: actions/checkout@v4
+ # with:
+ # persist-credentials: false
+ # - uses: actions/setup-python@v5
+ # with:
+ # python-version: '3.11'
+ # - name: Build with JIT enabled and GIL disabled
+ # run: |
+ # sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
+ # export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH"
+ # ./configure --enable-experimental-jit --with-pydebug --disable-gil
+ # make all --jobs 4
+ # - name: Run tests
+ # run: |
+ # ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml
index 5dfa8d7bcafd78..95133c1338b682 100644
--- a/.github/workflows/mypy.yml
+++ b/.github/workflows/mypy.yml
@@ -8,15 +8,23 @@ on:
pull_request:
paths:
- ".github/workflows/mypy.yml"
+ - "Lib/_colorize.py"
- "Lib/_pyrepl/**"
- "Lib/test/libregrtest/**"
+ - "Lib/tomllib/**"
+ - "Misc/mypy/**"
+ - "Tools/build/compute-changes.py"
+ - "Tools/build/deepfreeze.py"
- "Tools/build/generate_sbom.py"
+ - "Tools/build/generate-build-details.py"
+ - "Tools/build/verify_ensurepip_wheels.py"
+ - "Tools/build/update_file.py"
+ - "Tools/build/umarshal.py"
- "Tools/cases_generator/**"
- "Tools/clinic/**"
- "Tools/jit/**"
- "Tools/peg_generator/**"
- "Tools/requirements-dev.txt"
- - "Tools/wasm/**"
workflow_dispatch:
permissions:
@@ -33,22 +41,22 @@ concurrency:
jobs:
mypy:
+ name: Run mypy on ${{ matrix.target }}
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
strategy:
fail-fast: false
matrix:
target: [
"Lib/_pyrepl",
"Lib/test/libregrtest",
+ "Lib/tomllib",
"Tools/build",
"Tools/cases_generator",
"Tools/clinic",
"Tools/jit",
"Tools/peg_generator",
- "Tools/wasm",
]
- name: Run mypy on ${{ matrix.target }}
- runs-on: ubuntu-latest
- timeout-minutes: 10
steps:
- uses: actions/checkout@v4
with:
@@ -59,4 +67,5 @@ jobs:
cache: pip
cache-dependency-path: Tools/requirements-dev.txt
- run: pip install -r Tools/requirements-dev.txt
+ - run: python3 Misc/mypy/make_symlinks.py --symlink
- run: mypy --config-file ${{ matrix.target }}/mypy.ini
diff --git a/.github/workflows/project-updater.yml b/.github/workflows/project-updater.yml
index 066d8593a70cf6..1d9d637ec848a6 100644
--- a/.github/workflows/project-updater.yml
+++ b/.github/workflows/project-updater.yml
@@ -15,6 +15,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
+ fail-fast: false
matrix:
include:
# if an issue has any of these labels, it will be added
diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml
index 0a6277c779ff67..7e534c58c798d1 100644
--- a/.github/workflows/require-pr-label.yml
+++ b/.github/workflows/require-pr-label.yml
@@ -10,8 +10,7 @@ jobs:
if: github.repository_owner == 'python'
runs-on: ubuntu-latest
permissions:
- issues: write
- pull-requests: write
+ pull-requests: read
timeout-minutes: 10
steps:
@@ -28,8 +27,7 @@ jobs:
if: github.repository_owner == 'python'
runs-on: ubuntu-latest
permissions:
- issues: write
- pull-requests: write
+ pull-requests: read
timeout-minutes: 10
steps:
diff --git a/.github/workflows/reusable-context.yml b/.github/workflows/reusable-context.yml
index 73e036a146f5d4..d2668ddcac1a3d 100644
--- a/.github/workflows/reusable-context.yml
+++ b/.github/workflows/reusable-context.yml
@@ -97,6 +97,9 @@ jobs:
run: python Tools/build/compute-changes.py
env:
GITHUB_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
+ GITHUB_EVENT_NAME: ${{ github.event_name }}
+ CCF_TARGET_REF: ${{ github.base_ref || github.event.repository.default_branch }}
+ CCF_HEAD_REF: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Compute hash for config cache key
id: config-hash
diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml
index 6738acc98c6565..657e0a6bf662f7 100644
--- a/.github/workflows/reusable-docs.yml
+++ b/.github/workflows/reusable-docs.yml
@@ -15,7 +15,7 @@ env:
FORCE_COLOR: 1
jobs:
- build_doc:
+ build-doc:
name: 'Docs'
runs-on: ubuntu-latest
timeout-minutes: 60
@@ -66,7 +66,7 @@ jobs:
run: |
set -Eeuo pipefail
# Build docs with the nit-picky option; write warnings to file
- make -C Doc/ PYTHON=../python SPHINXOPTS="--quiet --nitpicky --fail-on-warning --keep-going --warning-file sphinx-warnings.txt" html
+ make -C Doc/ PYTHON=../python SPHINXOPTS="--quiet --nitpicky --fail-on-warning --warning-file sphinx-warnings.txt" html
- name: 'Check warnings'
if: github.event_name == 'pull_request'
run: |
@@ -101,4 +101,4 @@ jobs:
run: make -C Doc/ PYTHON=../python venv
# Use "xvfb-run" since some doctest tests open GUI windows
- name: 'Run documentation doctest'
- run: xvfb-run make -C Doc/ PYTHON=../python SPHINXERRORHANDLING="--fail-on-warning --keep-going" doctest
+ run: xvfb-run make -C Doc/ PYTHON=../python SPHINXERRORHANDLING="--fail-on-warning" doctest
diff --git a/.github/workflows/reusable-macos.yml b/.github/workflows/reusable-macos.yml
index 43ce0f957d2d49..de0c40221364ad 100644
--- a/.github/workflows/reusable-macos.yml
+++ b/.github/workflows/reusable-macos.yml
@@ -19,8 +19,9 @@ env:
FORCE_COLOR: 1
jobs:
- build_macos:
+ build-macos:
name: build and test (${{ inputs.os }})
+ runs-on: ${{ inputs.os }}
timeout-minutes: 60
env:
HOMEBREW_NO_ANALYTICS: 1
@@ -29,7 +30,6 @@ jobs:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
PYTHONSTRICTEXTENSIONBUILD: 1
TERM: linux
- runs-on: ${{ inputs.os }}
steps:
- uses: actions/checkout@v4
with:
diff --git a/.github/workflows/reusable-tsan.yml b/.github/workflows/reusable-tsan.yml
index 5c815f72f0ada5..6a58e5305f8e09 100644
--- a/.github/workflows/reusable-tsan.yml
+++ b/.github/workflows/reusable-tsan.yml
@@ -16,7 +16,7 @@ env:
FORCE_COLOR: 1
jobs:
- build_tsan_reusable:
+ build-tsan-reusable:
name: 'Thread sanitizer'
runs-on: ubuntu-24.04
timeout-minutes: 60
diff --git a/.github/workflows/reusable-ubuntu.yml b/.github/workflows/reusable-ubuntu.yml
index 9b366d4dfc212d..76b19fd5d1a72e 100644
--- a/.github/workflows/reusable-ubuntu.yml
+++ b/.github/workflows/reusable-ubuntu.yml
@@ -25,10 +25,10 @@ env:
FORCE_COLOR: 1
jobs:
- build_ubuntu_reusable:
+ build-ubuntu-reusable:
name: build and test (${{ inputs.os }})
- timeout-minutes: 60
runs-on: ${{ inputs.os }}
+ timeout-minutes: 60
env:
OPENSSL_VER: 3.0.15
PYTHONSTRICTEXTENSIONBUILD: 1
diff --git a/.github/workflows/reusable-wasi.yml b/.github/workflows/reusable-wasi.yml
index 36a0e4ef673260..6beb91e66d4027 100644
--- a/.github/workflows/reusable-wasi.yml
+++ b/.github/workflows/reusable-wasi.yml
@@ -11,10 +11,10 @@ env:
FORCE_COLOR: 1
jobs:
- build_wasi_reusable:
+ build-wasi-reusable:
name: 'build and test'
- timeout-minutes: 60
runs-on: ubuntu-24.04
+ timeout-minutes: 60
env:
WASMTIME_VERSION: 22.0.0
WASI_SDK_VERSION: 24
diff --git a/.github/workflows/reusable-windows-msi.yml b/.github/workflows/reusable-windows-msi.yml
index bc0414d1bbcd8f..a50de344bba4da 100644
--- a/.github/workflows/reusable-windows-msi.yml
+++ b/.github/workflows/reusable-windows-msi.yml
@@ -17,7 +17,7 @@ env:
jobs:
build:
name: installer for ${{ inputs.arch }}
- runs-on: windows-latest
+ runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-latest' }}
timeout-minutes: 60
env:
ARCH: ${{ inputs.arch }}
diff --git a/.github/workflows/reusable-windows.yml b/.github/workflows/reusable-windows.yml
index 5485a0169130b0..37c802095b0f2f 100644
--- a/.github/workflows/reusable-windows.yml
+++ b/.github/workflows/reusable-windows.yml
@@ -3,10 +3,6 @@ name: Reusable Windows
on:
workflow_call:
inputs:
- os:
- description: OS to run on
- required: true
- type: string
arch:
description: CPU architecture
required: true
@@ -24,8 +20,8 @@ env:
jobs:
build:
- name: ${{ inputs.arch == 'arm64' && 'build' || 'build and test' }} (${{ inputs.arch }})
- runs-on: ${{ inputs.os }}
+ name: Build and test (${{ inputs.arch }})
+ runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-latest' }}
timeout-minutes: 60
env:
ARCH: ${{ inputs.arch }}
@@ -43,11 +39,9 @@ jobs:
-p "${ARCH}"
${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
shell: bash
- - name: Display build info # FIXME(diegorusso): remove the `if`
- if: inputs.arch != 'arm64'
+ - name: Display build info
run: .\\python.bat -m test.pythoninfo
- - name: Tests # FIXME(diegorusso): remove the `if`
- if: inputs.arch != 'arm64'
+ - name: Tests
run: >-
.\\PCbuild\\rt.bat
-p "${ARCH}"
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index 7578189f5d4d67..febb2dd823a8fe 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -7,7 +7,6 @@ on:
jobs:
stale:
if: github.repository_owner == 'python'
-
runs-on: ubuntu-latest
permissions:
pull-requests: write
diff --git a/.github/workflows/tail-call.yml b/.github/workflows/tail-call.yml
index 33b37ca52fbdd0..4636372e26c41b 100644
--- a/.github/workflows/tail-call.yml
+++ b/.github/workflows/tail-call.yml
@@ -2,12 +2,14 @@ name: Tail calling interpreter
on:
pull_request:
paths:
+ - '.github/workflows/tail-call.yml'
- 'Python/bytecodes.c'
- 'Python/ceval.c'
- 'Python/ceval_macros.h'
- 'Python/generated_cases.c.h'
push:
paths:
+ - '.github/workflows/tail-call.yml'
- 'Python/bytecodes.c'
- 'Python/ceval.c'
- 'Python/ceval_macros.h'
@@ -35,7 +37,7 @@ jobs:
target:
# Un-comment as we add support for more platforms for tail-calling interpreters.
# - i686-pc-windows-msvc/msvc
-# - x86_64-pc-windows-msvc/msvc
+ - x86_64-pc-windows-msvc/msvc
# - aarch64-pc-windows-msvc/msvc
- x86_64-apple-darwin/clang
- aarch64-apple-darwin/clang
@@ -43,14 +45,14 @@ jobs:
- aarch64-unknown-linux-gnu/gcc
- free-threading
llvm:
- - 19
+ - 20
include:
# - target: i686-pc-windows-msvc/msvc
# architecture: Win32
# runner: windows-latest
-# - target: x86_64-pc-windows-msvc/msvc
-# architecture: x64
-# runner: windows-latest
+ - target: x86_64-pc-windows-msvc/msvc
+ architecture: x64
+ runner: windows-latest
# - target: aarch64-pc-windows-msvc/msvc
# architecture: ARM64
# runner: windows-latest
@@ -79,41 +81,51 @@ jobs:
- name: Native Windows (debug)
if: runner.os == 'Windows' && matrix.architecture != 'ARM64'
+ shell: cmd
run: |
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
- ./PCbuild/build.bat --tail-call-interp -d -p ${{ matrix.architecture }}
- ./PCbuild/rt.bat -d -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
+ set PlatformToolset=clangcl
+ set LLVMToolsVersion=${{ matrix.llvm }}.1.0
+ set LLVMInstallDir=C:\Program Files\LLVM
+ call ./PCbuild/build.bat --tail-call-interp -d -p ${{ matrix.architecture }}
+ call ./PCbuild/rt.bat -d -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
# No tests (yet):
- name: Emulated Windows (release)
if: runner.os == 'Windows' && matrix.architecture == 'ARM64'
+ shell: cmd
run: |
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
+ set PlatformToolset=clangcl
+ set LLVMToolsVersion=${{ matrix.llvm }}.1.0
+ set LLVMInstallDir=C:\Program Files\LLVM
./PCbuild/build.bat --tail-call-interp -p ${{ matrix.architecture }}
# The `find` line is required as a result of https://github.com/actions/runner-images/issues/9966.
# This is a bug in the macOS runner image where the pre-installed Python is installed in the same
# directory as the Homebrew Python, which causes the build to fail for macos-13. This line removes
# the symlink to the pre-installed Python so that the Homebrew Python is used instead.
- - name: Native macOS (debug)
+ # Note: when a new LLVM is released, the homebrew installation directory changes, so the builds will fail.
+ # We either need to upgrade LLVM or change the directory being pointed to.
+ - name: Native macOS (release)
if: runner.os == 'macOS'
run: |
brew update
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
brew install llvm@${{ matrix.llvm }}
export SDKROOT="$(xcrun --show-sdk-path)"
- export PATH="/opt/homebrew/opt/llvm/bin:$PATH"
export PATH="/usr/local/opt/llvm/bin:$PATH"
- CC=clang-19 ./configure --with-tail-call-interp --with-pydebug
+ export PATH="/opt/homebrew/opt/llvm/bin:$PATH"
+ CC=clang-20 ./configure --with-tail-call-interp
make all --jobs 4
./python.exe -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
- - name: Native Linux (release)
+ - name: Native Linux (debug)
if: runner.os == 'Linux' && matrix.target != 'free-threading'
run: |
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH"
- CC=clang-19 ./configure --with-tail-call-interp
+ CC=clang-20 ./configure --with-tail-call-interp --with-pydebug
make all --jobs 4
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
@@ -122,7 +134,7 @@ jobs:
run: |
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH"
- CC=clang-19 ./configure --with-tail-call-interp --disable-gil
+ CC=clang-20 ./configure --with-tail-call-interp --disable-gil
make all --jobs 4
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
diff --git a/.github/zizmor.yml b/.github/zizmor.yml
index eeda8d9eaaf484..9b42b47cc85545 100644
--- a/.github/zizmor.yml
+++ b/.github/zizmor.yml
@@ -4,3 +4,7 @@ rules:
dangerous-triggers:
ignore:
- documentation-links.yml
+ unpinned-uses:
+ config:
+ policies:
+ "*": ref-pin
diff --git a/.gitignore b/.gitignore
index 8872e9d5508ff1..2a6f249275c32e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@ tags
TAGS
.vs/
.vscode/
+.cache/
gmon.out
.coverage
.mypy_cache/
@@ -137,11 +138,12 @@ Tools/unicode/data/
# hendrikmuhs/ccache-action@v1
/.ccache
/cross-build/
-/jit_stencils.h
+/jit_stencils*.h
/platform
/profile-clean-stamp
/profile-run-stamp
/profile-bolt-stamp
+/profile-gen-stamp
/pybuilddir.txt
/pyconfig.h
/python-config
diff --git a/.mailmap b/.mailmap
index 013c839ed6b7a4..8f11bebb18fc17 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1,3 +1,4 @@
# This file sets the canonical name for contributors to the repository.
# Documentation: https://git-scm.com/docs/gitmailmap
+Willow Chargin
Amethyst Reese
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index fb44c27704d455..3632cf392039f5 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.9.1
+ rev: v0.11.8
hooks:
- id: ruff
name: Run Ruff (lint) on Doc/
@@ -11,9 +11,9 @@ repos:
args: [--exit-non-zero-on-fix]
files: ^Lib/test/
- id: ruff
- name: Run Ruff (lint) on Tools/build/check_warnings.py
+ name: Run Ruff (lint) on Tools/build/
args: [--exit-non-zero-on-fix, --config=Tools/build/.ruff.toml]
- files: ^Tools/build/check_warnings.py
+ files: ^Tools/build/
- id: ruff
name: Run Ruff (lint) on Argument Clinic
args: [--exit-non-zero-on-fix, --config=Tools/clinic/.ruff.toml]
@@ -22,14 +22,14 @@ repos:
name: Run Ruff (format) on Doc/
args: [--check]
files: ^Doc/
+ - id: ruff-format
+ name: Run Ruff (format) on Tools/build/check_warnings.py
+ args: [--check, --config=Tools/build/.ruff.toml]
+ files: ^Tools/build/check_warnings.py
- repo: https://github.com/psf/black-pre-commit-mirror
- rev: 24.10.0
+ rev: 25.1.0
hooks:
- - id: black
- name: Run Black on Tools/build/check_warnings.py
- files: ^Tools/build/check_warnings.py
- args: [--line-length=79]
- id: black
name: Run Black on Tools/jit/
files: ^Tools/jit/
@@ -47,9 +47,11 @@ repos:
exclude: Lib/test/tokenizedata/coding20731.py
- id: trailing-whitespace
types_or: [c, inc, python, rst]
+ - id: trailing-whitespace
+ files: '\.(gram)$'
- repo: https://github.com/python-jsonschema/check-jsonschema
- rev: 0.31.0
+ rev: 0.33.0
hooks:
- id: check-dependabot
- id: check-github-workflows
@@ -61,7 +63,7 @@ repos:
- id: actionlint
- repo: https://github.com/woodruffw/zizmor-pre-commit
- rev: v1.1.1
+ rev: v1.6.0
hooks:
- id: zizmor
diff --git a/.ruff.toml b/.ruff.toml
new file mode 100644
index 00000000000000..1c015fa88415bc
--- /dev/null
+++ b/.ruff.toml
@@ -0,0 +1,12 @@
+# Default settings for Ruff in CPython
+
+# PYTHON_FOR_REGEN
+target-version = "py310"
+
+# PEP 8
+line-length = 79
+
+# Enable automatic fixes by default.
+# To override this, use ``fix = false`` in a subdirectory's config file
+# or ``--no-fix`` on the command line.
+fix = true
diff --git a/Android/README.md b/Android/README.md
index 28d48917e4e5a8..6cabd6ba5d6844 100644
--- a/Android/README.md
+++ b/Android/README.md
@@ -1,19 +1,22 @@
# Python for Android
-These instructions are only needed if you're planning to compile Python for
-Android yourself. Most users should *not* need to do this. Instead, use one of
-the tools listed in `Doc/using/android.rst`, which will provide a much easier
-experience.
+If you obtained this README as part of a release package, then the only
+applicable sections are "Prerequisites", "Testing", and "Using in your own app".
+If you obtained this README as part of the CPython source tree, then you can
+also follow the other sections to compile Python for Android yourself.
+
+However, most app developers should not need to do any of these things manually.
+Instead, use one of the tools listed
+[here](https://docs.python.org/3/using/android.html), which will provide a much
+easier experience.
-## Prerequisites
-First, make sure you have all the usual tools and libraries needed to build
-Python for your development machine.
+## Prerequisites
-Second, you'll need an Android SDK. If you already have the SDK installed,
-export the `ANDROID_HOME` environment variable to point at its location.
-Otherwise, here's how to install it:
+If you already have an Android SDK installed, export the `ANDROID_HOME`
+environment variable to point at its location. Otherwise, here's how to install
+it:
* Download the "Command line tools" from .
* Create a directory `android-sdk/cmdline-tools`, and unzip the command line
@@ -22,20 +25,23 @@ Otherwise, here's how to install it:
`android-sdk/cmdline-tools/latest`.
* `export ANDROID_HOME=/path/to/android-sdk`
-The `android.py` script also requires the following commands to be on the `PATH`:
+The `android.py` script will automatically use the SDK's `sdkmanager` to install
+any packages it needs.
+
+The script also requires the following commands to be on the `PATH`:
* `curl`
* `java` (or set the `JAVA_HOME` environment variable)
-* `tar`
-* `unzip`
## Building
Python can be built for Android on any POSIX platform supported by the Android
-development tools, which currently means Linux or macOS. This involves doing a
-cross-build where you use a "build" Python (for your development machine) to
-help produce a "host" Python for Android.
+development tools, which currently means Linux or macOS.
+
+First we'll make a "build" Python (for your development machine), then use it to
+help produce a "host" Python for Android. So make sure you have all the usual
+tools and libraries needed to build Python for your development machine.
The easiest way to do a build is to use the `android.py` script. You can either
have it perform the entire build process from start to finish in one step, or
@@ -60,8 +66,8 @@ To do all steps in a single command, run:
./android.py build HOST
```
-In the end you should have a build Python in `cross-build/build`, and an Android
-build in `cross-build/HOST`.
+In the end you should have a build Python in `cross-build/build`, and a host
+Python in `cross-build/HOST`.
You can use `--` as a separator for any of the `configure`-related commands –
including `build` itself – to pass arguments to the underlying `configure`
@@ -73,14 +79,27 @@ call. For example, if you want a pydebug build that also caches the results from
```
+## Packaging
+
+After building an architecture as described in the section above, you can
+package it for release with this command:
+
+```sh
+./android.py package HOST
+```
+
+`HOST` is defined in the section above.
+
+This will generate a tarball in `cross-build/HOST/dist`, whose structure is
+similar to the `Android` directory of the CPython source tree.
+
+
## Testing
-The test suite can be run on Linux, macOS, or Windows:
+The Python test suite can be run on Linux, macOS, or Windows:
* On Linux, the emulator needs access to the KVM virtualization interface, and
- a DISPLAY environment variable pointing at an X server.
-* On Windows, you won't be able to do the build on the same machine, so you'll
- have to copy the `cross-build/HOST` directory from somewhere else.
+ a DISPLAY environment variable pointing at an X server. Xvfb is acceptable.
The test suite can usually be run on a device with 2 GB of RAM, but this is
borderline, so you may need to increase it to 4 GB. As of Android
@@ -90,9 +109,16 @@ and find `hw.ramSize` in both config.ini and hardware-qemu.ini. Either set these
manually to the same value, or use the Android Studio Device Manager, which will
update both files.
-Before running the test suite, follow the instructions in the previous section
-to build the architecture you want to test. Then run the test script in one of
-the following modes:
+You can run the test suite either:
+
+* Within the CPython repository, after doing a build as described above. On
+ Windows, you won't be able to do the build on the same machine, so you'll have
+ to copy the `cross-build/HOST/prefix` directory from somewhere else.
+
+* Or by taking a release package built using the `package` command, extracting
+ it wherever you want, and using its own copy of `android.py`.
+
+The test script supports the following modes:
* In `--connected` mode, it runs on a device or emulator you have already
connected to the build machine. List the available devices with
@@ -133,4 +159,4 @@ until you re-run `android.py make-host` or `build`.
## Using in your own app
-See `Doc/using/android.rst`.
+See https://docs.python.org/3/using/android.html.
diff --git a/Android/android.py b/Android/android.py
index ae630aa8f4427c..3f48b42aa17571 100755
--- a/Android/android.py
+++ b/Android/android.py
@@ -2,7 +2,6 @@
import asyncio
import argparse
-from glob import glob
import os
import re
import shlex
@@ -13,6 +12,8 @@
import sysconfig
from asyncio import wait_for
from contextlib import asynccontextmanager
+from datetime import datetime, timezone
+from glob import glob
from os.path import basename, relpath
from pathlib import Path
from subprocess import CalledProcessError
@@ -20,11 +21,12 @@
SCRIPT_NAME = Path(__file__).name
-CHECKOUT = Path(__file__).resolve().parent.parent
-ANDROID_DIR = CHECKOUT / "Android"
+ANDROID_DIR = Path(__file__).resolve().parent
+CHECKOUT = ANDROID_DIR.parent
TESTBED_DIR = ANDROID_DIR / "testbed"
CROSS_BUILD_DIR = CHECKOUT / "cross-build"
+HOSTS = ["aarch64-linux-android", "x86_64-linux-android"]
APP_ID = "org.python.testbed"
DECODE_ARGS = ("UTF-8", "backslashreplace")
@@ -58,12 +60,10 @@ def delete_glob(pattern):
path.unlink()
-def subdir(name, *, clean=None):
- path = CROSS_BUILD_DIR / name
- if clean:
- delete_glob(path)
+def subdir(*parts, create=False):
+ path = CROSS_BUILD_DIR.joinpath(*parts)
if not path.exists():
- if clean is None:
+ if not create:
sys.exit(
f"{path} does not exist. Create it by running the appropriate "
f"`configure` subcommand of {SCRIPT_NAME}.")
@@ -123,7 +123,9 @@ def build_python_path():
def configure_build_python(context):
- os.chdir(subdir("build", clean=context.clean))
+ if context.clean:
+ clean("build")
+ os.chdir(subdir("build", create=True))
command = [relpath(CHECKOUT / "configure")]
if context.args:
@@ -136,35 +138,33 @@ def make_build_python(context):
run(["make", "-j", str(os.cpu_count())])
-def unpack_deps(host):
+def unpack_deps(host, prefix_dir):
deps_url = "https://github.com/beeware/cpython-android-source-deps/releases/download"
for name_ver in ["bzip2-1.0.8-2", "libffi-3.4.4-3", "openssl-3.0.15-4",
- "sqlite-3.45.3-3", "xz-5.4.6-1"]:
+ "sqlite-3.49.1-0", "xz-5.4.6-1"]:
filename = f"{name_ver}-{host}.tar.gz"
download(f"{deps_url}/{name_ver}/{filename}")
- run(["tar", "-xf", filename])
+ shutil.unpack_archive(filename, prefix_dir)
os.remove(filename)
def download(url, target_dir="."):
out_path = f"{target_dir}/{basename(url)}"
- run(["curl", "-Lf", "-o", out_path, url])
+ run(["curl", "-Lf", "--retry", "5", "--retry-all-errors", "-o", out_path, url])
return out_path
def configure_host_python(context):
- host_dir = subdir(context.host, clean=context.clean)
+ if context.clean:
+ clean(context.host)
+ host_dir = subdir(context.host, create=True)
prefix_dir = host_dir / "prefix"
if not prefix_dir.exists():
prefix_dir.mkdir()
- os.chdir(prefix_dir)
- unpack_deps(context.host)
-
- build_dir = host_dir / "build"
- build_dir.mkdir(exist_ok=True)
- os.chdir(build_dir)
+ unpack_deps(context.host, prefix_dir)
+ os.chdir(host_dir)
command = [
# Basic cross-compiling configuration
relpath(CHECKOUT / "configure"),
@@ -193,11 +193,10 @@ def make_host_python(context):
# the build.
host_dir = subdir(context.host)
prefix_dir = host_dir / "prefix"
- delete_glob(f"{prefix_dir}/include/python*")
- delete_glob(f"{prefix_dir}/lib/libpython*")
- delete_glob(f"{prefix_dir}/lib/python*")
+ for pattern in ("include/python*", "lib/libpython*", "lib/python*"):
+ delete_glob(f"{prefix_dir}/{pattern}")
- os.chdir(host_dir / "build")
+ os.chdir(host_dir)
run(["make", "-j", str(os.cpu_count())], host=context.host)
run(["make", "install", f"prefix={prefix_dir}"], host=context.host)
@@ -209,8 +208,13 @@ def build_all(context):
step(context)
+def clean(host):
+ delete_glob(CROSS_BUILD_DIR / host)
+
+
def clean_all(context):
- delete_glob(CROSS_BUILD_DIR)
+ for host in HOSTS + ["build"]:
+ clean(host)
def setup_sdk():
@@ -234,31 +238,26 @@ def setup_sdk():
# To avoid distributing compiled artifacts without corresponding source code,
# the Gradle wrapper is not included in the CPython repository. Instead, we
-# extract it from the Gradle release.
+# extract it from the Gradle GitHub repository.
def setup_testbed():
- if all((TESTBED_DIR / path).exists() for path in [
- "gradlew", "gradlew.bat", "gradle/wrapper/gradle-wrapper.jar",
- ]):
+ paths = ["gradlew", "gradlew.bat", "gradle/wrapper/gradle-wrapper.jar"]
+ if all((TESTBED_DIR / path).exists() for path in paths):
return
- ver_long = "8.7.0"
- ver_short = ver_long.removesuffix(".0")
-
- for filename in ["gradlew", "gradlew.bat"]:
- out_path = download(
- f"https://raw.githubusercontent.com/gradle/gradle/v{ver_long}/{filename}",
- TESTBED_DIR)
+ # The wrapper version isn't important, as any version of the wrapper can
+ # download any version of Gradle. The Gradle version actually used for the
+ # build is specified in testbed/gradle/wrapper/gradle-wrapper.properties.
+ version = "8.9.0"
+
+ for path in paths:
+ out_path = TESTBED_DIR / path
+ out_path.parent.mkdir(exist_ok=True)
+ download(
+ f"https://raw.githubusercontent.com/gradle/gradle/v{version}/{path}",
+ out_path.parent,
+ )
os.chmod(out_path, 0o755)
- with TemporaryDirectory(prefix=SCRIPT_NAME) as temp_dir:
- bin_zip = download(
- f"https://services.gradle.org/distributions/gradle-{ver_short}-bin.zip",
- temp_dir)
- outer_jar = f"gradle-{ver_short}/lib/plugins/gradle-wrapper-{ver_short}.jar"
- run(["unzip", "-d", temp_dir, bin_zip, outer_jar])
- run(["unzip", "-o", "-d", f"{TESTBED_DIR}/gradle/wrapper",
- f"{temp_dir}/{outer_jar}", "gradle-wrapper.jar"])
-
# run_testbed will build the app automatically, but it's useful to have this as
# a separate command to allow running the app outside of this script.
@@ -538,6 +537,73 @@ async def run_testbed(context):
raise e.exceptions[0]
+def package_version(prefix_dir):
+ patchlevel_glob = f"{prefix_dir}/include/python*/patchlevel.h"
+ patchlevel_paths = glob(patchlevel_glob)
+ if len(patchlevel_paths) != 1:
+ sys.exit(f"{patchlevel_glob} matched {len(patchlevel_paths)} paths.")
+
+ for line in open(patchlevel_paths[0]):
+ if match := re.fullmatch(r'\s*#define\s+PY_VERSION\s+"(.+)"\s*', line):
+ version = match[1]
+ break
+ else:
+ sys.exit(f"Failed to find Python version in {patchlevel_paths[0]}.")
+
+ # If not building against a tagged commit, add a timestamp to the version.
+ # Follow the PyPA version number rules, as this will make it easier to
+ # process with other tools.
+ if version.endswith("+"):
+ version += datetime.now(timezone.utc).strftime("%Y%m%d.%H%M%S")
+
+ return version
+
+
+def package(context):
+ prefix_dir = subdir(context.host, "prefix")
+ version = package_version(prefix_dir)
+
+ with TemporaryDirectory(prefix=SCRIPT_NAME) as temp_dir:
+ temp_dir = Path(temp_dir)
+
+ # Include all tracked files from the Android directory.
+ for line in run(
+ ["git", "ls-files"],
+ cwd=ANDROID_DIR, capture_output=True, text=True, log=False,
+ ).stdout.splitlines():
+ src = ANDROID_DIR / line
+ dst = temp_dir / line
+ dst.parent.mkdir(parents=True, exist_ok=True)
+ shutil.copy2(src, dst, follow_symlinks=False)
+
+ # Include anything from the prefix directory which could be useful
+ # either for embedding Python in an app, or building third-party
+ # packages against it.
+ for rel_dir, patterns in [
+ ("include", ["openssl*", "python*", "sqlite*"]),
+ ("lib", ["engines-3", "libcrypto*.so", "libpython*", "libsqlite*",
+ "libssl*.so", "ossl-modules", "python*"]),
+ ("lib/pkgconfig", ["*crypto*", "*ssl*", "*python*", "*sqlite*"]),
+ ]:
+ for pattern in patterns:
+ for src in glob(f"{prefix_dir}/{rel_dir}/{pattern}"):
+ dst = temp_dir / relpath(src, prefix_dir.parent)
+ dst.parent.mkdir(parents=True, exist_ok=True)
+ if Path(src).is_dir():
+ shutil.copytree(
+ src, dst, symlinks=True,
+ ignore=lambda *args: ["__pycache__"]
+ )
+ else:
+ shutil.copy2(src, dst, follow_symlinks=False)
+
+ dist_dir = subdir(context.host, "dist", create=True)
+ package_path = shutil.make_archive(
+ f"{dist_dir}/python-{version}-{context.host}", "gztar", temp_dir
+ )
+ print(f"Wrote {package_path}")
+
+
# Handle SIGTERM the same way as SIGINT. This ensures that if we're terminated
# by the buildbot worker, we'll make an attempt to clean up our subprocesses.
def install_signal_handler():
@@ -550,6 +616,8 @@ def signal_handler(*args):
def parse_args():
parser = argparse.ArgumentParser()
subcommands = parser.add_subparsers(dest="subcommand")
+
+ # Subcommands
build = subcommands.add_parser("build", help="Build everything")
configure_build = subcommands.add_parser("configure-build",
help="Run `configure` for the "
@@ -561,25 +629,27 @@ def parse_args():
make_host = subcommands.add_parser("make-host",
help="Run `make` for Android")
subcommands.add_parser(
- "clean", help="Delete the cross-build directory")
+ "clean", help="Delete all build and prefix directories")
+ subcommands.add_parser(
+ "build-testbed", help="Build the testbed app")
+ test = subcommands.add_parser(
+ "test", help="Run the test suite")
+ package = subcommands.add_parser("package", help="Make a release package")
+ # Common arguments
for subcommand in build, configure_build, configure_host:
subcommand.add_argument(
"--clean", action="store_true", default=False, dest="clean",
- help="Delete any relevant directories before building")
- for subcommand in build, configure_host, make_host:
+ help="Delete the relevant build and prefix directories first")
+ for subcommand in [build, configure_host, make_host, package]:
subcommand.add_argument(
- "host", metavar="HOST",
- choices=["aarch64-linux-android", "x86_64-linux-android"],
+ "host", metavar="HOST", choices=HOSTS,
help="Host triplet: choices=[%(choices)s]")
for subcommand in build, configure_build, configure_host:
subcommand.add_argument("args", nargs="*",
help="Extra arguments to pass to `configure`")
- subcommands.add_parser(
- "build-testbed", help="Build the testbed app")
- test = subcommands.add_parser(
- "test", help="Run the test suite")
+ # Test arguments
test.add_argument(
"-v", "--verbose", action="count", default=0,
help="Show Gradle output, and non-Python logcat messages. "
@@ -608,14 +678,17 @@ def main():
stream.reconfigure(line_buffering=True)
context = parse_args()
- dispatch = {"configure-build": configure_build_python,
- "make-build": make_build_python,
- "configure-host": configure_host_python,
- "make-host": make_host_python,
- "build": build_all,
- "clean": clean_all,
- "build-testbed": build_testbed,
- "test": run_testbed}
+ dispatch = {
+ "configure-build": configure_build_python,
+ "make-build": make_build_python,
+ "configure-host": configure_host_python,
+ "make-host": make_host_python,
+ "build": build_all,
+ "clean": clean_all,
+ "build-testbed": build_testbed,
+ "test": run_testbed,
+ "package": package,
+ }
try:
result = dispatch[context.subcommand](context)
diff --git a/Android/testbed/.gitignore b/Android/testbed/.gitignore
index b9a7d611c943cf..7c57aee58c160a 100644
--- a/Android/testbed/.gitignore
+++ b/Android/testbed/.gitignore
@@ -1,18 +1,19 @@
-# The Gradle wrapper should be downloaded by running `../android.py setup-testbed`.
+# The Gradle wrapper can be downloaded by running the `test` or `build-testbed`
+# commands of android.py.
/gradlew
/gradlew.bat
/gradle/wrapper/gradle-wrapper.jar
+# The repository's top-level .gitignore file ignores all .idea directories, but
+# we want to keep any files which can't be regenerated from the Gradle
+# configuration.
+!.idea/
+/.idea/*
+!/.idea/inspectionProfiles
+
*.iml
.gradle
/local.properties
-/.idea/caches
-/.idea/deploymentTargetDropdown.xml
-/.idea/libraries
-/.idea/modules.xml
-/.idea/workspace.xml
-/.idea/navEditor.xml
-/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
diff --git a/Android/testbed/.idea/inspectionProfiles/Project_Default.xml b/Android/testbed/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 00000000000000..220d9ed4ef20f7
--- /dev/null
+++ b/Android/testbed/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Android/testbed/app/build.gradle.kts b/Android/testbed/app/build.gradle.kts
index 211b5bbfadf64d..c627cb1b0e0b22 100644
--- a/Android/testbed/app/build.gradle.kts
+++ b/Android/testbed/app/build.gradle.kts
@@ -6,28 +6,71 @@ plugins {
id("org.jetbrains.kotlin.android")
}
-val PYTHON_DIR = file("../../..").canonicalPath
-val PYTHON_CROSS_DIR = "$PYTHON_DIR/cross-build"
-
-val ABIS = mapOf(
- "arm64-v8a" to "aarch64-linux-android",
- "x86_64" to "x86_64-linux-android",
-).filter { file("$PYTHON_CROSS_DIR/${it.value}").exists() }
-if (ABIS.isEmpty()) {
+val ANDROID_DIR = file("../..")
+val PYTHON_DIR = ANDROID_DIR.parentFile!!
+val PYTHON_CROSS_DIR = file("$PYTHON_DIR/cross-build")
+val inSourceTree = (
+ ANDROID_DIR.name == "Android" && file("$PYTHON_DIR/pyconfig.h.in").exists()
+)
+
+val KNOWN_ABIS = mapOf(
+ "aarch64-linux-android" to "arm64-v8a",
+ "x86_64-linux-android" to "x86_64",
+)
+
+// Discover prefixes.
+val prefixes = ArrayList()
+if (inSourceTree) {
+ for ((triplet, _) in KNOWN_ABIS.entries) {
+ val prefix = file("$PYTHON_CROSS_DIR/$triplet/prefix")
+ if (prefix.exists()) {
+ prefixes.add(prefix)
+ }
+ }
+} else {
+ // Testbed is inside a release package.
+ val prefix = file("$ANDROID_DIR/prefix")
+ if (prefix.exists()) {
+ prefixes.add(prefix)
+ }
+}
+if (prefixes.isEmpty()) {
throw GradleException(
- "No Android ABIs found in $PYTHON_CROSS_DIR: see Android/README.md " +
- "for building instructions."
+ "No Android prefixes found: see README.md for testing instructions"
)
}
-val PYTHON_VERSION = file("$PYTHON_DIR/Include/patchlevel.h").useLines {
- for (line in it) {
- val match = """#define PY_VERSION\s+"(\d+\.\d+)""".toRegex().find(line)
- if (match != null) {
- return@useLines match.groupValues[1]
+// Detect Python versions and ABIs.
+lateinit var pythonVersion: String
+var abis = HashMap()
+for ((i, prefix) in prefixes.withIndex()) {
+ val libDir = file("$prefix/lib")
+ val version = run {
+ for (filename in libDir.list()!!) {
+ """python(\d+\.\d+)""".toRegex().matchEntire(filename)?.let {
+ return@run it.groupValues[1]
+ }
}
+ throw GradleException("Failed to find Python version in $libDir")
+ }
+ if (i == 0) {
+ pythonVersion = version
+ } else if (pythonVersion != version) {
+ throw GradleException(
+ "${prefixes[0]} is Python $pythonVersion, but $prefix is Python $version"
+ )
}
- throw GradleException("Failed to find Python version")
+
+ val libPythonDir = file("$libDir/python$pythonVersion")
+ val triplet = run {
+ for (filename in libPythonDir.list()!!) {
+ """_sysconfigdata__android_(.+).py""".toRegex().matchEntire(filename)?.let {
+ return@run it.groupValues[1]
+ }
+ }
+ throw GradleException("Failed to find Python triplet in $libPythonDir")
+ }
+ abis[prefix] = KNOWN_ABIS[triplet]!!
}
@@ -53,10 +96,16 @@ android {
versionCode = 1
versionName = "1.0"
- ndk.abiFilters.addAll(ABIS.keys)
+ ndk.abiFilters.addAll(abis.values)
externalNativeBuild.cmake.arguments(
- "-DPYTHON_CROSS_DIR=$PYTHON_CROSS_DIR",
- "-DPYTHON_VERSION=$PYTHON_VERSION",
+ "-DPYTHON_PREFIX_DIR=" + if (inSourceTree) {
+ // AGP uses the ${} syntax for its own purposes, so use a Jinja style
+ // placeholder.
+ "$PYTHON_CROSS_DIR/{{triplet}}/prefix"
+ } else {
+ prefixes[0]
+ },
+ "-DPYTHON_VERSION=$pythonVersion",
"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON",
)
@@ -133,24 +182,25 @@ dependencies {
// Create some custom tasks to copy Python and its standard library from
// elsewhere in the repository.
androidComponents.onVariants { variant ->
- val pyPlusVer = "python$PYTHON_VERSION"
+ val pyPlusVer = "python$pythonVersion"
generateTask(variant, variant.sources.assets!!) {
into("python") {
+ // Include files such as pyconfig.h are used by some of the tests.
into("include/$pyPlusVer") {
- for (triplet in ABIS.values) {
- from("$PYTHON_CROSS_DIR/$triplet/prefix/include/$pyPlusVer")
+ for (prefix in prefixes) {
+ from("$prefix/include/$pyPlusVer")
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
into("lib/$pyPlusVer") {
- // To aid debugging, the source directory takes priority.
- from("$PYTHON_DIR/Lib")
-
- // The cross-build directory provides ABI-specific files such as
- // sysconfigdata.
- for (triplet in ABIS.values) {
- from("$PYTHON_CROSS_DIR/$triplet/prefix/lib/$pyPlusVer")
+ // To aid debugging, the source directory takes priority when
+ // running inside a CPython source tree.
+ if (inSourceTree) {
+ from("$PYTHON_DIR/Lib")
+ }
+ for (prefix in prefixes) {
+ from("$prefix/lib/$pyPlusVer")
}
into("site-packages") {
@@ -164,9 +214,9 @@ androidComponents.onVariants { variant ->
}
generateTask(variant, variant.sources.jniLibs!!) {
- for ((abi, triplet) in ABIS.entries) {
+ for ((prefix, abi) in abis.entries) {
into(abi) {
- from("$PYTHON_CROSS_DIR/$triplet/prefix/lib")
+ from("$prefix/lib")
include("libpython*.*.so")
include("lib*_python.so")
}
diff --git a/Android/testbed/app/src/main/c/CMakeLists.txt b/Android/testbed/app/src/main/c/CMakeLists.txt
index 1d5df9a73465b6..6d5ccd96f8ae29 100644
--- a/Android/testbed/app/src/main/c/CMakeLists.txt
+++ b/Android/testbed/app/src/main/c/CMakeLists.txt
@@ -1,9 +1,14 @@
cmake_minimum_required(VERSION 3.4.1)
project(testbed)
-set(PREFIX_DIR ${PYTHON_CROSS_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}/prefix)
-include_directories(${PREFIX_DIR}/include/python${PYTHON_VERSION})
-link_directories(${PREFIX_DIR}/lib)
+# Resolve variables from the command line.
+string(
+ REPLACE {{triplet}} ${CMAKE_LIBRARY_ARCHITECTURE}
+ PYTHON_PREFIX_DIR ${PYTHON_PREFIX_DIR}
+)
+
+include_directories(${PYTHON_PREFIX_DIR}/include/python${PYTHON_VERSION})
+link_directories(${PYTHON_PREFIX_DIR}/lib)
link_libraries(log python${PYTHON_VERSION})
add_library(main_activity SHARED main_activity.c)
diff --git a/Doc/.ruff.toml b/Doc/.ruff.toml
index 111ce03b91df38..3e676e13c3f41a 100644
--- a/Doc/.ruff.toml
+++ b/Doc/.ruff.toml
@@ -1,7 +1,6 @@
+extend = "../.ruff.toml" # Inherit the project-wide settings
+
target-version = "py312" # Align with the version in oldest_supported_sphinx
-fix = true
-output-format = "full"
-line-length = 79
extend-exclude = [
"includes/*",
# Temporary exclusions:
diff --git a/Doc/Makefile b/Doc/Makefile
index b8896da4a91869..c8a749a02a89ec 100644
--- a/Doc/Makefile
+++ b/Doc/Makefile
@@ -204,6 +204,7 @@ dist-html:
find dist -name 'python-$(DISTVERSION)-docs-html*' -exec rm -rf {} \;
$(MAKE) html
cp -pPR build/html dist/python-$(DISTVERSION)-docs-html
+ rm -rf dist/python-$(DISTVERSION)-docs-html/_images/social_previews/
tar -C dist -cf dist/python-$(DISTVERSION)-docs-html.tar python-$(DISTVERSION)-docs-html
bzip2 -9 -k dist/python-$(DISTVERSION)-docs-html.tar
(cd dist; zip -q -r -9 python-$(DISTVERSION)-docs-html.zip python-$(DISTVERSION)-docs-html)
diff --git a/Doc/c-api/allocation.rst b/Doc/c-api/allocation.rst
index b7e0f22b52c57e..f8d01a3f29b30e 100644
--- a/Doc/c-api/allocation.rst
+++ b/Doc/c-api/allocation.rst
@@ -16,7 +16,20 @@ Allocating Objects on the Heap
Initialize a newly allocated object *op* with its type and initial
reference. Returns the initialized object. Other fields of the object are
- not affected.
+ not initialized. Despite its name, this function is unrelated to the
+ object's :meth:`~object.__init__` method (:c:member:`~PyTypeObject.tp_init`
+ slot). Specifically, this function does **not** call the object's
+ :meth:`!__init__` method.
+
+ In general, consider this function to be a low-level routine. Use
+ :c:member:`~PyTypeObject.tp_alloc` where possible.
+ For implementing :c:member:`!tp_alloc` for your type, prefer
+ :c:func:`PyType_GenericAlloc` or :c:func:`PyObject_New`.
+
+ .. note::
+
+ This function only initializes the object's memory corresponding to the
+ initial :c:type:`PyObject` structure. It does not zero the rest.
.. c:function:: PyVarObject* PyObject_InitVar(PyVarObject *op, PyTypeObject *type, Py_ssize_t size)
@@ -24,30 +37,107 @@ Allocating Objects on the Heap
This does everything :c:func:`PyObject_Init` does, and also initializes the
length information for a variable-size object.
+ .. note::
+
+ This function only initializes some of the object's memory. It does not
+ zero the rest.
+
.. c:macro:: PyObject_New(TYPE, typeobj)
- Allocate a new Python object using the C structure type *TYPE*
- and the Python type object *typeobj* (``PyTypeObject*``).
- Fields not defined by the Python object header are not initialized.
- The caller will own the only reference to the object
- (i.e. its reference count will be one).
- The size of the memory allocation is determined from the
- :c:member:`~PyTypeObject.tp_basicsize` field of the type object.
+ Allocates a new Python object using the C structure type *TYPE* and the
+ Python type object *typeobj* (``PyTypeObject*``) by calling
+ :c:func:`PyObject_Malloc` to allocate memory and initializing it like
+ :c:func:`PyObject_Init`. The caller will own the only reference to the
+ object (i.e. its reference count will be one).
+
+ Avoid calling this directly to allocate memory for an object; call the type's
+ :c:member:`~PyTypeObject.tp_alloc` slot instead.
+
+ When populating a type's :c:member:`~PyTypeObject.tp_alloc` slot,
+ :c:func:`PyType_GenericAlloc` is preferred over a custom function that
+ simply calls this macro.
+
+ This macro does not call :c:member:`~PyTypeObject.tp_alloc`,
+ :c:member:`~PyTypeObject.tp_new` (:meth:`~object.__new__`), or
+ :c:member:`~PyTypeObject.tp_init` (:meth:`~object.__init__`).
+
+ This cannot be used for objects with :c:macro:`Py_TPFLAGS_HAVE_GC` set in
+ :c:member:`~PyTypeObject.tp_flags`; use :c:macro:`PyObject_GC_New` instead.
+
+ Memory allocated by this macro must be freed with :c:func:`PyObject_Free`
+ (usually called via the object's :c:member:`~PyTypeObject.tp_free` slot).
+
+ .. note::
+
+ The returned memory is not guaranteed to have been completely zeroed
+ before it was initialized.
+
+ .. note::
+
+ This macro does not construct a fully initialized object of the given
+ type; it merely allocates memory and prepares it for further
+ initialization by :c:member:`~PyTypeObject.tp_init`. To construct a
+ fully initialized object, call *typeobj* instead. For example::
+
+ PyObject *foo = PyObject_CallNoArgs((PyObject *)&PyFoo_Type);
+
+ .. seealso::
+
+ * :c:func:`PyObject_Free`
+ * :c:macro:`PyObject_GC_New`
+ * :c:func:`PyType_GenericAlloc`
+ * :c:member:`~PyTypeObject.tp_alloc`
.. c:macro:: PyObject_NewVar(TYPE, typeobj, size)
- Allocate a new Python object using the C structure type *TYPE* and the
- Python type object *typeobj* (``PyTypeObject*``).
- Fields not defined by the Python object header
- are not initialized. The allocated memory allows for the *TYPE* structure
- plus *size* (``Py_ssize_t``) fields of the size
- given by the :c:member:`~PyTypeObject.tp_itemsize` field of
- *typeobj*. This is useful for implementing objects like tuples, which are
- able to determine their size at construction time. Embedding the array of
- fields into the same allocation decreases the number of allocations,
- improving the memory management efficiency.
+ Like :c:macro:`PyObject_New` except:
+
+ * It allocates enough memory for the *TYPE* structure plus *size*
+ (``Py_ssize_t``) fields of the size given by the
+ :c:member:`~PyTypeObject.tp_itemsize` field of *typeobj*.
+ * The memory is initialized like :c:func:`PyObject_InitVar`.
+
+ This is useful for implementing objects like tuples, which are able to
+ determine their size at construction time. Embedding the array of fields
+ into the same allocation decreases the number of allocations, improving the
+ memory management efficiency.
+
+ Avoid calling this directly to allocate memory for an object; call the type's
+ :c:member:`~PyTypeObject.tp_alloc` slot instead.
+
+ When populating a type's :c:member:`~PyTypeObject.tp_alloc` slot,
+ :c:func:`PyType_GenericAlloc` is preferred over a custom function that
+ simply calls this macro.
+
+ This cannot be used for objects with :c:macro:`Py_TPFLAGS_HAVE_GC` set in
+ :c:member:`~PyTypeObject.tp_flags`; use :c:macro:`PyObject_GC_NewVar`
+ instead.
+
+ Memory allocated by this function must be freed with :c:func:`PyObject_Free`
+ (usually called via the object's :c:member:`~PyTypeObject.tp_free` slot).
+
+ .. note::
+
+ The returned memory is not guaranteed to have been completely zeroed
+ before it was initialized.
+
+ .. note::
+
+ This macro does not construct a fully initialized object of the given
+ type; it merely allocates memory and prepares it for further
+ initialization by :c:member:`~PyTypeObject.tp_init`. To construct a
+ fully initialized object, call *typeobj* instead. For example::
+
+ PyObject *list_instance = PyObject_CallNoArgs((PyObject *)&PyList_Type);
+
+ .. seealso::
+
+ * :c:func:`PyObject_Free`
+ * :c:macro:`PyObject_GC_NewVar`
+ * :c:func:`PyType_GenericAlloc`
+ * :c:member:`~PyTypeObject.tp_alloc`
.. c:function:: void PyObject_Del(void *op)
diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst
index deebaba1952999..3bbc990b6329c0 100644
--- a/Doc/c-api/arg.rst
+++ b/Doc/c-api/arg.rst
@@ -5,7 +5,7 @@
Parsing arguments and building values
=====================================
-These functions are useful when creating your own extensions functions and
+These functions are useful when creating your own extension functions and
methods. Additional information and examples are available in
:ref:`extending-index`.
@@ -113,14 +113,18 @@ There are three ways strings and buffers can be converted to C:
``z`` (:class:`str` or ``None``) [const char \*]
Like ``s``, but the Python object may also be ``None``, in which case the C
pointer is set to ``NULL``.
+ It is the same as ``s?`` with the C pointer was initialized to ``NULL``.
``z*`` (:class:`str`, :term:`bytes-like object` or ``None``) [Py_buffer]
Like ``s*``, but the Python object may also be ``None``, in which case the
``buf`` member of the :c:type:`Py_buffer` structure is set to ``NULL``.
+ It is the same as ``s*?`` with the ``buf`` member of the :c:type:`Py_buffer`
+ structure was initialized to ``NULL``.
``z#`` (:class:`str`, read-only :term:`bytes-like object` or ``None``) [const char \*, :c:type:`Py_ssize_t`]
Like ``s#``, but the Python object may also be ``None``, in which case the C
pointer is set to ``NULL``.
+ It is the same as ``s#?`` with the C pointer was initialized to ``NULL``.
``y`` (read-only :term:`bytes-like object`) [const char \*]
This format converts a bytes-like object to a C pointer to a
@@ -270,6 +274,9 @@ small to receive the value.
Convert a Python integer to a C :c:expr:`unsigned long` without
overflow checking.
+ .. versionchanged:: 3.14
+ Use :meth:`~object.__index__` if available.
+
``L`` (:class:`int`) [long long]
Convert a Python integer to a C :c:expr:`long long`.
@@ -277,6 +284,9 @@ small to receive the value.
Convert a Python integer to a C :c:expr:`unsigned long long`
without overflow checking.
+ .. versionchanged:: 3.14
+ Use :meth:`~object.__index__` if available.
+
``n`` (:class:`int`) [:c:type:`Py_ssize_t`]
Convert a Python integer to a C :c:type:`Py_ssize_t`.
@@ -357,11 +367,37 @@ Other objects
.. versionadded:: 3.3
-``(items)`` (:class:`tuple`) [*matching-items*]
- The object must be a Python sequence whose length is the number of format units
+``(items)`` (sequence) [*matching-items*]
+ The object must be a Python sequence (except :class:`str`, :class:`bytes`
+ or :class:`bytearray`) whose length is the number of format units
in *items*. The C arguments must correspond to the individual format units in
*items*. Format units for sequences may be nested.
+ If *items* contains format units which store a :ref:`borrowed buffer
+ ` (``s``, ``s#``, ``z``, ``z#``, ``y``, or ``y#``)
+ or a :term:`borrowed reference` (``S``, ``Y``, ``U``, ``O``, or ``O!``),
+ the object must be a Python tuple.
+ The *converter* for the ``O&`` format unit in *items* must not store
+ a borrowed buffer or a borrowed reference.
+
+ .. versionchanged:: 3.14
+ :class:`str` and :class:`bytearray` objects no longer accepted as a sequence.
+
+ .. deprecated:: 3.14
+ Non-tuple sequences are deprecated if *items* contains format units
+ which store a borrowed buffer or a borrowed reference.
+
+``unit?`` (anything or ``None``) [*matching-variable(s)*]
+ ``?`` modifies the behavior of the preceding format unit.
+ The C variable(s) corresponding to that parameter should be initialized
+ to their default value --- when the argument is ``None``,
+ :c:func:`PyArg_ParseTuple` does not touch the contents of the corresponding
+ C variable(s).
+ If the argument is not ``None``, it is parsed according to the specified
+ format unit.
+
+ .. versionadded:: 3.14
+
A few other characters have a meaning in a format string. These may not occur
inside nested parentheses. They are:
@@ -639,6 +675,8 @@ Building values
``L`` (:class:`int`) [long long]
Convert a C :c:expr:`long long` to a Python integer object.
+ .. _capi-py-buildvalue-format-K:
+
``K`` (:class:`int`) [unsigned long long]
Convert a C :c:expr:`unsigned long long` to a Python integer object.
diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst
index dc43a3d5fcb094..d3081894eadaf5 100644
--- a/Doc/c-api/buffer.rst
+++ b/Doc/c-api/buffer.rst
@@ -26,17 +26,19 @@ characteristic of being backed by a possibly large memory buffer. It is
then desirable, in some situations, to access that buffer directly and
without intermediate copying.
-Python provides such a facility at the C level in the form of the :ref:`buffer
-protocol `. This protocol has two sides:
+Python provides such a facility at the C and Python level in the form of the
+:ref:`buffer protocol `. This protocol has two sides:
.. index:: single: PyBufferProcs (C type)
- on the producer side, a type can export a "buffer interface" which allows
objects of that type to expose information about their underlying buffer.
- This interface is described in the section :ref:`buffer-structs`;
+ This interface is described in the section :ref:`buffer-structs`; for
+ Python see :ref:`python-buffer-protocol`.
- on the consumer side, several means are available to obtain a pointer to
- the raw underlying data of an object (for example a method parameter).
+ the raw underlying data of an object (for example a method parameter). For
+ Python see :class:`memoryview`.
Simple objects such as :class:`bytes` and :class:`bytearray` expose their
underlying buffer in byte-oriented form. Other forms are possible; for example,
@@ -62,6 +64,10 @@ In both cases, :c:func:`PyBuffer_Release` must be called when the buffer
isn't needed anymore. Failure to do so could lead to various issues such as
resource leaks.
+.. versionadded:: 3.12
+
+ The buffer protocol is now accessible in Python, see
+ :ref:`python-buffer-protocol` and :class:`memoryview`.
.. _buffer-structure:
diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst
index d1f5d8eda676ef..16bd79475dc1e6 100644
--- a/Doc/c-api/complex.rst
+++ b/Doc/c-api/complex.rst
@@ -44,36 +44,12 @@ pointers. This is consistent throughout the API.
representation.
-.. c:function:: Py_complex _Py_cr_sum(Py_complex left, double right)
-
- Return the sum of a complex number and a real number, using the C :c:type:`Py_complex`
- representation.
-
- .. versionadded:: 3.14
-
-
.. c:function:: Py_complex _Py_c_diff(Py_complex left, Py_complex right)
Return the difference between two complex numbers, using the C
:c:type:`Py_complex` representation.
-.. c:function:: Py_complex _Py_cr_diff(Py_complex left, double right)
-
- Return the difference between a complex number and a real number, using the C
- :c:type:`Py_complex` representation.
-
- .. versionadded:: 3.14
-
-
-.. c:function:: Py_complex _Py_rc_diff(double left, Py_complex right)
-
- Return the difference between a real number and a complex number, using the C
- :c:type:`Py_complex` representation.
-
- .. versionadded:: 3.14
-
-
.. c:function:: Py_complex _Py_c_neg(Py_complex num)
Return the negation of the complex number *num*, using the C
@@ -86,14 +62,6 @@ pointers. This is consistent throughout the API.
representation.
-.. c:function:: Py_complex _Py_cr_prod(Py_complex left, double right)
-
- Return the product of a complex number and a real number, using the C
- :c:type:`Py_complex` representation.
-
- .. versionadded:: 3.14
-
-
.. c:function:: Py_complex _Py_c_quot(Py_complex dividend, Py_complex divisor)
Return the quotient of two complex numbers, using the C :c:type:`Py_complex`
@@ -103,28 +71,6 @@ pointers. This is consistent throughout the API.
:c:data:`errno` to :c:macro:`!EDOM`.
-.. c:function:: Py_complex _Py_cr_quot(Py_complex dividend, double divisor)
-
- Return the quotient of a complex number and a real number, using the C
- :c:type:`Py_complex` representation.
-
- If *divisor* is zero, this method returns zero and sets
- :c:data:`errno` to :c:macro:`!EDOM`.
-
- .. versionadded:: 3.14
-
-
-.. c:function:: Py_complex _Py_rc_quot(double dividend, Py_complex divisor)
-
- Return the quotient of a real number and a complex number, using the C
- :c:type:`Py_complex` representation.
-
- If *divisor* is zero, this method returns zero and sets
- :c:data:`errno` to :c:macro:`!EDOM`.
-
- .. versionadded:: 3.14
-
-
.. c:function:: Py_complex _Py_c_pow(Py_complex num, Py_complex exp)
Return the exponentiation of *num* by *exp*, using the C :c:type:`Py_complex`
diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst
index ce73fa0cc60ebb..e55c5c80cb83c0 100644
--- a/Doc/c-api/dict.rst
+++ b/Doc/c-api/dict.rst
@@ -127,7 +127,7 @@ Dictionary Objects
Prefer the :c:func:`PyDict_GetItemWithError` function instead.
.. versionchanged:: 3.10
- Calling this API without :term:`GIL` held had been allowed for historical
+ Calling this API without an :term:`attached thread state` had been allowed for historical
reason. It is no longer allowed.
diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst
index 19f6baf9b3dc90..c8e1b5c2461738 100644
--- a/Doc/c-api/exceptions.rst
+++ b/Doc/c-api/exceptions.rst
@@ -413,7 +413,7 @@ Querying the error indicator
own a reference to the return value, so you do not need to :c:func:`Py_DECREF`
it.
- The caller must hold the GIL.
+ The caller must have an :term:`attached thread state`.
.. note::
@@ -675,7 +675,7 @@ Signal Handling
.. note::
This function is async-signal-safe. It can be called without
- the :term:`GIL` and from a C signal handler.
+ an :term:`attached thread state` and from a C signal handler.
.. c:function:: int PyErr_SetInterruptEx(int signum)
@@ -702,7 +702,7 @@ Signal Handling
.. note::
This function is async-signal-safe. It can be called without
- the :term:`GIL` and from a C signal handler.
+ an :term:`attached thread state` and from a C signal handler.
.. versionadded:: 3.10
diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst
index 1da37a5bcaeef9..c5a7653efca26b 100644
--- a/Doc/c-api/float.rst
+++ b/Doc/c-api/float.rst
@@ -96,6 +96,9 @@ NaNs (if such things exist on the platform) isn't handled correctly, and
attempting to unpack a bytes string containing an IEEE INF or NaN will raise an
exception.
+Note that NaNs type may not be preserved on IEEE platforms (silent NaN become
+quiet), for example on x86 systems in 32-bit mode.
+
On non-IEEE platforms with more precision, or larger dynamic range, than IEEE
754 supports, not all values can be packed; on non-IEEE platforms with less
precision, or smaller dynamic range, not all values can be unpacked. What
diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst
index 621da3eb069949..f6fa52b36c5ab3 100644
--- a/Doc/c-api/gcsupport.rst
+++ b/Doc/c-api/gcsupport.rst
@@ -57,11 +57,49 @@ rules:
Analogous to :c:macro:`PyObject_New` but for container objects with the
:c:macro:`Py_TPFLAGS_HAVE_GC` flag set.
+ Do not call this directly to allocate memory for an object; call the type's
+ :c:member:`~PyTypeObject.tp_alloc` slot instead.
+
+ When populating a type's :c:member:`~PyTypeObject.tp_alloc` slot,
+ :c:func:`PyType_GenericAlloc` is preferred over a custom function that
+ simply calls this macro.
+
+ Memory allocated by this macro must be freed with
+ :c:func:`PyObject_GC_Del` (usually called via the object's
+ :c:member:`~PyTypeObject.tp_free` slot).
+
+ .. seealso::
+
+ * :c:func:`PyObject_GC_Del`
+ * :c:macro:`PyObject_New`
+ * :c:func:`PyType_GenericAlloc`
+ * :c:member:`~PyTypeObject.tp_alloc`
+
+
.. c:macro:: PyObject_GC_NewVar(TYPE, typeobj, size)
Analogous to :c:macro:`PyObject_NewVar` but for container objects with the
:c:macro:`Py_TPFLAGS_HAVE_GC` flag set.
+ Do not call this directly to allocate memory for an object; call the type's
+ :c:member:`~PyTypeObject.tp_alloc` slot instead.
+
+ When populating a type's :c:member:`~PyTypeObject.tp_alloc` slot,
+ :c:func:`PyType_GenericAlloc` is preferred over a custom function that
+ simply calls this macro.
+
+ Memory allocated by this macro must be freed with
+ :c:func:`PyObject_GC_Del` (usually called via the object's
+ :c:member:`~PyTypeObject.tp_free` slot).
+
+ .. seealso::
+
+ * :c:func:`PyObject_GC_Del`
+ * :c:macro:`PyObject_NewVar`
+ * :c:func:`PyType_GenericAlloc`
+ * :c:member:`~PyTypeObject.tp_alloc`
+
+
.. c:function:: PyObject* PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *type, size_t extra_size)
Analogous to :c:macro:`PyObject_GC_New` but allocates *extra_size*
@@ -73,6 +111,10 @@ rules:
The extra data will be deallocated with the object, but otherwise it is
not managed by Python.
+ Memory allocated by this function must be freed with
+ :c:func:`PyObject_GC_Del` (usually called via the object's
+ :c:member:`~PyTypeObject.tp_free` slot).
+
.. warning::
The function is marked as unstable because the final mechanism
for reserving extra data after an instance is not yet decided.
@@ -136,6 +178,21 @@ rules:
Releases memory allocated to an object using :c:macro:`PyObject_GC_New` or
:c:macro:`PyObject_GC_NewVar`.
+ Do not call this directly to free an object's memory; call the type's
+ :c:member:`~PyTypeObject.tp_free` slot instead.
+
+ Do not use this for memory allocated by :c:macro:`PyObject_New`,
+ :c:macro:`PyObject_NewVar`, or related allocation functions; use
+ :c:func:`PyObject_Free` instead.
+
+ .. seealso::
+
+ * :c:func:`PyObject_Free` is the non-GC equivalent of this function.
+ * :c:macro:`PyObject_GC_New`
+ * :c:macro:`PyObject_GC_NewVar`
+ * :c:func:`PyType_GenericAlloc`
+ * :c:member:`~PyTypeObject.tp_free`
+
.. c:function:: void PyObject_GC_UnTrack(void *op)
@@ -180,9 +237,9 @@ provided. In order to use this macro, the :c:member:`~PyTypeObject.tp_traverse`
must name its arguments exactly *visit* and *arg*:
-.. c:function:: void Py_VISIT(PyObject *o)
+.. c:macro:: Py_VISIT(o)
- If *o* is not ``NULL``, call the *visit* callback, with arguments *o*
+ If the :c:expr:`PyObject *` *o* is not ``NULL``, call the *visit* callback, with arguments *o*
and *arg*. If *visit* returns a non-zero value, then return it.
Using this macro, :c:member:`~PyTypeObject.tp_traverse` handlers
look like::
@@ -277,7 +334,7 @@ the garbage collector.
Type of the visitor function to be passed to :c:func:`PyUnstable_GC_VisitObjects`.
*arg* is the same as the *arg* passed to ``PyUnstable_GC_VisitObjects``.
- Return ``0`` to continue iteration, return ``1`` to stop iteration. Other return
+ Return ``1`` to continue iteration, return ``0`` to stop iteration. Other return
values are reserved for now so behavior on returning anything else is undefined.
.. versionadded:: 3.12
diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst
index 1cab3ce3061ec9..8eabc0406b11ce 100644
--- a/Doc/c-api/import.rst
+++ b/Doc/c-api/import.rst
@@ -16,19 +16,6 @@ Importing Modules
This is a wrapper around :c:func:`PyImport_Import()` which takes a
:c:expr:`const char *` as an argument instead of a :c:expr:`PyObject *`.
-.. c:function:: PyObject* PyImport_ImportModuleNoBlock(const char *name)
-
- This function is a deprecated alias of :c:func:`PyImport_ImportModule`.
-
- .. versionchanged:: 3.3
- This function used to fail immediately when the import lock was held
- by another thread. In Python 3.3 though, the locking scheme switched
- to per-module locks for most purposes, so this function's special
- behaviour isn't needed anymore.
-
- .. deprecated-removed:: 3.13 3.15
- Use :c:func:`PyImport_ImportModule` instead.
-
.. c:function:: PyObject* PyImport_ImportModuleEx(const char *name, PyObject *globals, PyObject *locals, PyObject *fromlist)
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index 9197f704fab344..9c866438b487d0 100644
--- a/Doc/c-api/init.rst
+++ b/Doc/c-api/init.rst
@@ -77,10 +77,7 @@ The following functions can be safely called before Python is initialized:
Despite their apparent similarity to some of the functions listed above,
the following functions **should not be called** before the interpreter has
- been initialized: :c:func:`Py_EncodeLocale`, :c:func:`Py_GetPath`,
- :c:func:`Py_GetPrefix`, :c:func:`Py_GetExecPrefix`,
- :c:func:`Py_GetProgramFullPath`, :c:func:`Py_GetPythonHome`,
- :c:func:`Py_GetProgramName`, :c:func:`PyEval_InitThreads`, and
+ been initialized: :c:func:`Py_EncodeLocale`, :c:func:`PyEval_InitThreads`, and
:c:func:`Py_RunMain`.
@@ -145,9 +142,6 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2.
:c:member:`PyConfig.pathconfig_warnings` should be used instead, see
:ref:`Python Initialization Configuration `.
- Suppress error messages when calculating the module search path in
- :c:func:`Py_GetPath`.
-
Private flag used by ``_freeze_module`` and ``frozenmain`` programs.
.. deprecated-removed:: 3.12 3.15
@@ -203,7 +197,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2.
Set by the :option:`-i` option.
- .. deprecated:: 3.12
+ .. deprecated-removed:: 3.12 3.15
.. c:var:: int Py_IsolatedFlag
@@ -573,7 +567,7 @@ Initializing and finalizing the interpreter
This is similar to :c:func:`Py_AtExit`, but takes an explicit interpreter and
data pointer for the callback.
- The :term:`GIL` must be held for *interp*.
+ There must be an :term:`attached thread state` for *interp*.
.. versionadded:: 3.13
@@ -586,7 +580,6 @@ Process-wide parameters
.. index::
single: Py_Initialize()
single: main()
- single: Py_GetPath()
This API is kept for backward compatibility: setting
:c:member:`PyConfig.program_name` should be used instead, see :ref:`Python
@@ -596,7 +589,7 @@ Process-wide parameters
the first time, if it is called at all. It tells the interpreter the value
of the ``argv[0]`` argument to the :c:func:`main` function of the program
(converted to wide characters).
- This is used by :c:func:`Py_GetPath` and some other functions below to find
+ This is used by some other functions below to find
the Python run-time libraries relative to the interpreter executable. The
default value is ``'python'``. The argument should point to a
zero-terminated wide character string in static storage whose contents will not
@@ -609,146 +602,6 @@ Process-wide parameters
.. deprecated-removed:: 3.11 3.15
-.. c:function:: wchar_t* Py_GetProgramName()
-
- Return the program name set with :c:member:`PyConfig.program_name`, or the default.
- The returned string points into static storage; the caller should not modify its
- value.
-
- This function should not be called before :c:func:`Py_Initialize`, otherwise
- it returns ``NULL``.
-
- .. versionchanged:: 3.10
- It now returns ``NULL`` if called before :c:func:`Py_Initialize`.
-
- .. deprecated-removed:: 3.13 3.15
- Use :c:func:`PyConfig_Get("executable") `
- (:data:`sys.executable`) instead.
-
-
-.. c:function:: wchar_t* Py_GetPrefix()
-
- Return the *prefix* for installed platform-independent files. This is derived
- through a number of complicated rules from the program name set with
- :c:member:`PyConfig.program_name` and some environment variables; for example, if the
- program name is ``'/usr/local/bin/python'``, the prefix is ``'/usr/local'``. The
- returned string points into static storage; the caller should not modify its
- value. This corresponds to the :makevar:`prefix` variable in the top-level
- :file:`Makefile` and the :option:`--prefix` argument to the :program:`configure`
- script at build time. The value is available to Python code as ``sys.base_prefix``.
- It is only useful on Unix. See also the next function.
-
- This function should not be called before :c:func:`Py_Initialize`, otherwise
- it returns ``NULL``.
-
- .. versionchanged:: 3.10
- It now returns ``NULL`` if called before :c:func:`Py_Initialize`.
-
- .. deprecated-removed:: 3.13 3.15
- Use :c:func:`PyConfig_Get("base_prefix") `
- (:data:`sys.base_prefix`) instead. Use :c:func:`PyConfig_Get("prefix")
- ` (:data:`sys.prefix`) if :ref:`virtual environments
- ` need to be handled.
-
-
-.. c:function:: wchar_t* Py_GetExecPrefix()
-
- Return the *exec-prefix* for installed platform-*dependent* files. This is
- derived through a number of complicated rules from the program name set with
- :c:member:`PyConfig.program_name` and some environment variables; for example, if the
- program name is ``'/usr/local/bin/python'``, the exec-prefix is
- ``'/usr/local'``. The returned string points into static storage; the caller
- should not modify its value. This corresponds to the :makevar:`exec_prefix`
- variable in the top-level :file:`Makefile` and the ``--exec-prefix``
- argument to the :program:`configure` script at build time. The value is
- available to Python code as ``sys.base_exec_prefix``. It is only useful on
- Unix.
-
- Background: The exec-prefix differs from the prefix when platform dependent
- files (such as executables and shared libraries) are installed in a different
- directory tree. In a typical installation, platform dependent files may be
- installed in the :file:`/usr/local/plat` subtree while platform independent may
- be installed in :file:`/usr/local`.
-
- Generally speaking, a platform is a combination of hardware and software
- families, e.g. Sparc machines running the Solaris 2.x operating system are
- considered the same platform, but Intel machines running Solaris 2.x are another
- platform, and Intel machines running Linux are yet another platform. Different
- major revisions of the same operating system generally also form different
- platforms. Non-Unix operating systems are a different story; the installation
- strategies on those systems are so different that the prefix and exec-prefix are
- meaningless, and set to the empty string. Note that compiled Python bytecode
- files are platform independent (but not independent from the Python version by
- which they were compiled!).
-
- System administrators will know how to configure the :program:`mount` or
- :program:`automount` programs to share :file:`/usr/local` between platforms
- while having :file:`/usr/local/plat` be a different filesystem for each
- platform.
-
- This function should not be called before :c:func:`Py_Initialize`, otherwise
- it returns ``NULL``.
-
- .. versionchanged:: 3.10
- It now returns ``NULL`` if called before :c:func:`Py_Initialize`.
-
- .. deprecated-removed:: 3.13 3.15
- Use :c:func:`PyConfig_Get("base_exec_prefix") `
- (:data:`sys.base_exec_prefix`) instead. Use
- :c:func:`PyConfig_Get("exec_prefix") `
- (:data:`sys.exec_prefix`) if :ref:`virtual environments ` need
- to be handled.
-
-.. c:function:: wchar_t* Py_GetProgramFullPath()
-
- .. index::
- single: executable (in module sys)
-
- Return the full program name of the Python executable; this is computed as a
- side-effect of deriving the default module search path from the program name
- (set by :c:member:`PyConfig.program_name`). The returned string points into
- static storage; the caller should not modify its value. The value is available
- to Python code as ``sys.executable``.
-
- This function should not be called before :c:func:`Py_Initialize`, otherwise
- it returns ``NULL``.
-
- .. versionchanged:: 3.10
- It now returns ``NULL`` if called before :c:func:`Py_Initialize`.
-
- .. deprecated-removed:: 3.13 3.15
- Use :c:func:`PyConfig_Get("executable") `
- (:data:`sys.executable`) instead.
-
-
-.. c:function:: wchar_t* Py_GetPath()
-
- .. index::
- triple: module; search; path
- single: path (in module sys)
-
- Return the default module search path; this is computed from the program name
- (set by :c:member:`PyConfig.program_name`) and some environment variables.
- The returned string consists of a series of directory names separated by a
- platform dependent delimiter character. The delimiter character is ``':'``
- on Unix and macOS, ``';'`` on Windows. The returned string points into
- static storage; the caller should not modify its value. The list
- :data:`sys.path` is initialized with this value on interpreter startup; it
- can be (and usually is) modified later to change the search path for loading
- modules.
-
- This function should not be called before :c:func:`Py_Initialize`, otherwise
- it returns ``NULL``.
-
- .. XXX should give the exact rules
-
- .. versionchanged:: 3.10
- It now returns ``NULL`` if called before :c:func:`Py_Initialize`.
-
- .. deprecated-removed:: 3.13 3.15
- Use :c:func:`PyConfig_Get("module_search_paths") `
- (:data:`sys.path`) instead.
-
.. c:function:: const char* Py_GetVersion()
Return the version of this Python interpreter. This is a string that looks
@@ -919,23 +772,6 @@ Process-wide parameters
.. deprecated-removed:: 3.11 3.15
-.. c:function:: wchar_t* Py_GetPythonHome()
-
- Return the default "home", that is, the value set by
- :c:member:`PyConfig.home`, or the value of the :envvar:`PYTHONHOME`
- environment variable if it is set.
-
- This function should not be called before :c:func:`Py_Initialize`, otherwise
- it returns ``NULL``.
-
- .. versionchanged:: 3.10
- It now returns ``NULL`` if called before :c:func:`Py_Initialize`.
-
- .. deprecated-removed:: 3.13 3.15
- Use :c:func:`PyConfig_Get("home") ` or the
- :envvar:`PYTHONHOME` environment variable instead.
-
-
.. _threads:
Thread State and the Global Interpreter Lock
@@ -946,7 +782,8 @@ Thread State and the Global Interpreter Lock
single: interpreter lock
single: lock, interpreter
-The Python interpreter is not fully thread-safe. In order to support
+Unless on a :term:`free-threaded ` build of :term:`CPython`,
+the Python interpreter is not fully thread-safe. In order to support
multi-threaded Python programs, there's a global lock, called the :term:`global
interpreter lock` or :term:`GIL`, that must be held by the current thread before
it can safely access Python objects. Without the lock, even the simplest
@@ -967,20 +804,30 @@ a file, so that other Python threads can run in the meantime.
single: PyThreadState (C type)
The Python interpreter keeps some thread-specific bookkeeping information
-inside a data structure called :c:type:`PyThreadState`. There's also one
-global variable pointing to the current :c:type:`PyThreadState`: it can
-be retrieved using :c:func:`PyThreadState_Get`.
-
-Releasing the GIL from extension code
--------------------------------------
-
-Most extension code manipulating the :term:`GIL` has the following simple
+inside a data structure called :c:type:`PyThreadState`, known as a :term:`thread state`.
+Each OS thread has a thread-local pointer to a :c:type:`PyThreadState`; a thread state
+referenced by this pointer is considered to be :term:`attached `.
+
+A thread can only have one :term:`attached thread state` at a time. An attached
+thread state is typically analogous with holding the :term:`GIL`, except on
+:term:`free-threaded ` builds. On builds with the :term:`GIL` enabled,
+:term:`attaching ` a thread state will block until the :term:`GIL`
+can be acquired. However, even on builds with the :term:`GIL` disabled, it is still required
+to have an attached thread state to call most of the C API.
+
+In general, there will always be an :term:`attached thread state` when using Python's C API.
+Only in some specific cases (such as in a :c:macro:`Py_BEGIN_ALLOW_THREADS` block) will the
+thread not have an attached thread state. If uncertain, check if :c:func:`PyThreadState_GetUnchecked` returns
+``NULL``.
+
+Detaching the thread state from extension code
+----------------------------------------------
+
+Most extension code manipulating the :term:`thread state` has the following simple
structure::
Save the thread state in a local variable.
- Release the global interpreter lock.
... Do some blocking I/O operation ...
- Reacquire the global interpreter lock.
Restore the thread state from the local variable.
This is so common that a pair of macros exists to simplify it::
@@ -1009,21 +856,30 @@ The block above expands to the following code::
single: PyEval_RestoreThread (C function)
single: PyEval_SaveThread (C function)
-Here is how these functions work: the global interpreter lock is used to protect the pointer to the
-current thread state. When releasing the lock and saving the thread state,
-the current thread state pointer must be retrieved before the lock is released
-(since another thread could immediately acquire the lock and store its own thread
-state in the global variable). Conversely, when acquiring the lock and restoring
-the thread state, the lock must be acquired before storing the thread state
-pointer.
+Here is how these functions work:
+
+The :term:`attached thread state` holds the :term:`GIL` for the entire interpreter. When detaching
+the :term:`attached thread state`, the :term:`GIL` is released, allowing other threads to attach
+a thread state to their own thread, thus getting the :term:`GIL` and can start executing.
+The pointer to the prior :term:`attached thread state` is stored as a local variable.
+Upon reaching :c:macro:`Py_END_ALLOW_THREADS`, the thread state that was
+previously :term:`attached ` is passed to :c:func:`PyEval_RestoreThread`.
+This function will block until another releases its :term:`thread state `,
+thus allowing the old :term:`thread state ` to get re-attached and the
+C API can be called again.
+
+For :term:`free-threaded ` builds, the :term:`GIL` is normally
+out of the question, but detaching the :term:`thread state ` is still required
+for blocking I/O and long operations. The difference is that threads don't have to wait for the :term:`GIL`
+to be released to attach their thread state, allowing true multi-core parallelism.
.. note::
- Calling system I/O functions is the most common use case for releasing
- the GIL, but it can also be useful before calling long-running computations
- which don't need access to Python objects, such as compression or
- cryptographic functions operating over memory buffers. For example, the
- standard :mod:`zlib` and :mod:`hashlib` modules release the GIL when
- compressing or hashing data.
+ Calling system I/O functions is the most common use case for detaching
+ the :term:`thread state `, but it can also be useful before calling
+ long-running computations which don't need access to Python objects, such
+ as compression or cryptographic functions operating over memory buffers.
+ For example, the standard :mod:`zlib` and :mod:`hashlib` modules detach the
+ :term:`thread state ` when compressing or hashing data.
.. _gilstate:
@@ -1035,16 +891,15 @@ When threads are created using the dedicated Python APIs (such as the
:mod:`threading` module), a thread state is automatically associated to them
and the code showed above is therefore correct. However, when threads are
created from C (for example by a third-party library with its own thread
-management), they don't hold the GIL, nor is there a thread state structure
-for them.
+management), they don't hold the :term:`GIL`, because they don't have an
+:term:`attached thread state`.
If you need to call Python code from these threads (often this will be part
of a callback API provided by the aforementioned third-party library),
you must first register these threads with the interpreter by
-creating a thread state data structure, then acquiring the GIL, and finally
-storing their thread state pointer, before you can start using the Python/C
-API. When you are done, you should reset the thread state pointer, release
-the GIL, and finally free the thread state data structure.
+creating an :term:`attached thread state` before you can start using the Python/C
+API. When you are done, you should detach the :term:`thread state `, and
+finally free it.
The :c:func:`PyGILState_Ensure` and :c:func:`PyGILState_Release` functions do
all of the above automatically. The typical idiom for calling into Python
@@ -1064,8 +919,36 @@ Note that the ``PyGILState_*`` functions assume there is only one global
interpreter (created automatically by :c:func:`Py_Initialize`). Python
supports the creation of additional interpreters (using
:c:func:`Py_NewInterpreter`), but mixing multiple interpreters and the
-``PyGILState_*`` API is unsupported.
+``PyGILState_*`` API is unsupported. This is because :c:func:`PyGILState_Ensure`
+and similar functions default to :term:`attaching ` a
+:term:`thread state` for the main interpreter, meaning that the thread can't safely
+interact with the calling subinterpreter.
+
+Supporting subinterpreters in non-Python threads
+------------------------------------------------
+
+If you would like to support subinterpreters with non-Python created threads, you
+must use the ``PyThreadState_*`` API instead of the traditional ``PyGILState_*``
+API.
+
+In particular, you must store the interpreter state from the calling
+function and pass it to :c:func:`PyThreadState_New`, which will ensure that
+the :term:`thread state` is targeting the correct interpreter::
+
+ /* The return value of PyInterpreterState_Get() from the
+ function that created this thread. */
+ PyInterpreterState *interp = ThreadData->interp;
+ PyThreadState *tstate = PyThreadState_New(interp);
+ PyThreadState_Swap(tstate);
+
+ /* GIL of the subinterpreter is now held.
+ Perform Python actions here. */
+ result = CallSomeFunction();
+ /* evaluate result or handle exception */
+ /* Destroy the thread state. No Python API allowed beyond this point. */
+ PyThreadState_Clear(tstate);
+ PyThreadState_DeleteCurrent();
.. _fork-and-threads:
@@ -1112,26 +995,23 @@ Cautions regarding runtime finalization
In the late stage of :term:`interpreter shutdown`, after attempting to wait for
non-daemon threads to exit (though this can be interrupted by
:class:`KeyboardInterrupt`) and running the :mod:`atexit` functions, the runtime
-is marked as *finalizing*: :c:func:`_Py_IsFinalizing` and
+is marked as *finalizing*: :c:func:`Py_IsFinalizing` and
:func:`sys.is_finalizing` return true. At this point, only the *finalization
thread* that initiated finalization (typically the main thread) is allowed to
acquire the :term:`GIL`.
-If any thread, other than the finalization thread, attempts to acquire the GIL
-during finalization, either explicitly via :c:func:`PyGILState_Ensure`,
-:c:macro:`Py_END_ALLOW_THREADS`, :c:func:`PyEval_AcquireThread`, or
-:c:func:`PyEval_AcquireLock`, or implicitly when the interpreter attempts to
-reacquire it after having yielded it, the thread enters **a permanently blocked
-state** where it remains until the program exits. In most cases this is
-harmless, but this can result in deadlock if a later stage of finalization
-attempts to acquire a lock owned by the blocked thread, or otherwise waits on
-the blocked thread.
+If any thread, other than the finalization thread, attempts to attach a :term:`thread state`
+during finalization, either explicitly or
+implicitly, the thread enters **a permanently blocked state**
+where it remains until the program exits. In most cases this is harmless, but this can result
+in deadlock if a later stage of finalization attempts to acquire a lock owned by the
+blocked thread, or otherwise waits on the blocked thread.
Gross? Yes. This prevents random crashes and/or unexpectedly skipped C++
finalizations further up the call stack when such threads were forcibly exited
-here in CPython 3.13 and earlier. The CPython runtime GIL acquiring C APIs
-have never had any error reporting or handling expectations at GIL acquisition
-time that would've allowed for graceful exit from this situation. Changing that
+here in CPython 3.13 and earlier. The CPython runtime :term:`thread state` C APIs
+have never had any error reporting or handling expectations at :term:`thread state`
+attachment time that would've allowed for graceful exit from this situation. Changing that
would require new stable C APIs and rewriting the majority of C code in the
CPython ecosystem to use those with error handling.
@@ -1194,18 +1074,15 @@ code, or when embedding the Python interpreter:
.. c:function:: PyThreadState* PyEval_SaveThread()
- Release the global interpreter lock (if it has been created) and reset the
- thread state to ``NULL``, returning the previous thread state (which is not
- ``NULL``). If the lock has been created, the current thread must have
- acquired it.
+ Detach the :term:`attached thread state` and return it.
+ The thread will have no :term:`thread state` upon returning.
.. c:function:: void PyEval_RestoreThread(PyThreadState *tstate)
- Acquire the global interpreter lock (if it has been created) and set the
- thread state to *tstate*, which must not be ``NULL``. If the lock has been
- created, the current thread must not have acquired it, otherwise deadlock
- ensues.
+ Set the :term:`attached thread state` to *tstate*.
+ The passed :term:`thread state` **should not** be :term:`attached `,
+ otherwise deadlock ensues. *tstate* will be attached upon returning.
.. note::
Calling this function from a thread when the runtime is finalizing will
@@ -1219,13 +1096,13 @@ code, or when embedding the Python interpreter:
.. c:function:: PyThreadState* PyThreadState_Get()
- Return the current thread state. The global interpreter lock must be held.
- When the current thread state is ``NULL``, this issues a fatal error (so that
- the caller needn't check for ``NULL``).
+ Return the :term:`attached thread state`. If the thread has no attached
+ thread state, (such as when inside of :c:macro:`Py_BEGIN_ALLOW_THREADS`
+ block), then this issues a fatal error (so that the caller needn't check
+ for ``NULL``).
See also :c:func:`PyThreadState_GetUnchecked`.
-
.. c:function:: PyThreadState* PyThreadState_GetUnchecked()
Similar to :c:func:`PyThreadState_Get`, but don't kill the process with a
@@ -1239,9 +1116,18 @@ code, or when embedding the Python interpreter:
.. c:function:: PyThreadState* PyThreadState_Swap(PyThreadState *tstate)
- Swap the current thread state with the thread state given by the argument
- *tstate*, which may be ``NULL``. The global interpreter lock must be held
- and is not released.
+ Set the :term:`attached thread state` to *tstate*, and return the
+ :term:`thread state` that was attached prior to calling.
+
+ This function is safe to call without an :term:`attached thread state`; it
+ will simply return ``NULL`` indicating that there was no prior thread state.
+
+ .. seealso:
+ :c:func:`PyEval_ReleaseThread`
+
+ .. note::
+ Similar to :c:func:`PyGILState_Ensure`, this function will hang the
+ thread if the runtime is finalizing.
The following functions use thread-local storage, and are not compatible
@@ -1250,7 +1136,7 @@ with sub-interpreters:
.. c:function:: PyGILState_STATE PyGILState_Ensure()
Ensure that the current thread is ready to call the Python C API regardless
- of the current state of Python, or of the global interpreter lock. This may
+ of the current state of Python, or of the :term:`attached thread state`. This may
be called as many times as desired by a thread as long as each call is
matched with a call to :c:func:`PyGILState_Release`. In general, other
thread-related APIs may be used between :c:func:`PyGILState_Ensure` and
@@ -1259,20 +1145,20 @@ with sub-interpreters:
:c:macro:`Py_BEGIN_ALLOW_THREADS` and :c:macro:`Py_END_ALLOW_THREADS` macros is
acceptable.
- The return value is an opaque "handle" to the thread state when
+ The return value is an opaque "handle" to the :term:`attached thread state` when
:c:func:`PyGILState_Ensure` was called, and must be passed to
:c:func:`PyGILState_Release` to ensure Python is left in the same state. Even
though recursive calls are allowed, these handles *cannot* be shared - each
unique call to :c:func:`PyGILState_Ensure` must save the handle for its call
to :c:func:`PyGILState_Release`.
- When the function returns, the current thread will hold the GIL and be able
- to call arbitrary Python code. Failure is a fatal error.
+ When the function returns, there will be an :term:`attached thread state`
+ and the thread will be able to call arbitrary Python code. Failure is a fatal error.
- .. note::
- Calling this function from a thread when the runtime is finalizing will
- hang the thread until the program exits, even if the thread was not
- created by Python. Refer to
+ .. warning::
+ Calling this function when the runtime is finalizing is unsafe. Doing
+ so will either hang the thread until the program ends, or fully crash
+ the interpreter in rare cases. Refer to
:ref:`cautions-regarding-runtime-finalization` for more details.
.. versionchanged:: 3.14
@@ -1289,26 +1175,37 @@ with sub-interpreters:
Every call to :c:func:`PyGILState_Ensure` must be matched by a call to
:c:func:`PyGILState_Release` on the same thread.
-
.. c:function:: PyThreadState* PyGILState_GetThisThreadState()
- Get the current thread state for this thread. May return ``NULL`` if no
+ Get the :term:`attached thread state` for this thread. May return ``NULL`` if no
GILState API has been used on the current thread. Note that the main thread
always has such a thread-state, even if no auto-thread-state call has been
made on the main thread. This is mainly a helper/diagnostic function.
+ .. note::
+ This function does not account for :term:`thread states ` created
+ by something other than :c:func:`PyGILState_Ensure` (such as :c:func:`PyThreadState_New`).
+ Prefer :c:func:`PyThreadState_Get` or :c:func:`PyThreadState_GetUnchecked`
+ for most cases.
+
+ .. seealso: :c:func:`PyThreadState_Get``
.. c:function:: int PyGILState_Check()
- Return ``1`` if the current thread is holding the GIL and ``0`` otherwise.
+ Return ``1`` if the current thread is holding the :term:`GIL` and ``0`` otherwise.
This function can be called from any thread at any time.
- Only if it has had its Python thread state initialized and currently is
- holding the GIL will it return ``1``.
+ Only if it has had its :term:`thread state ` initialized
+ via :c:func:`PyGILState_Ensure` will it return ``1``.
This is mainly a helper/diagnostic function. It can be useful
for example in callback contexts or memory allocation functions when
- knowing that the GIL is locked can allow the caller to perform sensitive
+ knowing that the :term:`GIL` is locked can allow the caller to perform sensitive
actions or otherwise behave differently.
+ .. note::
+ If the current Python process has ever created a subinterpreter, this
+ function will *always* return ``1``. Prefer :c:func:`PyThreadState_GetUnchecked`
+ for most cases.
+
.. versionadded:: 3.4
@@ -1351,13 +1248,14 @@ Low-level API
All of the following functions must be called after :c:func:`Py_Initialize`.
.. versionchanged:: 3.7
- :c:func:`Py_Initialize()` now initializes the :term:`GIL`.
+ :c:func:`Py_Initialize()` now initializes the :term:`GIL`
+ and sets an :term:`attached thread state`.
.. c:function:: PyInterpreterState* PyInterpreterState_New()
- Create a new interpreter state object. The global interpreter lock need not
- be held, but may be held if it is necessary to serialize calls to this
+ Create a new interpreter state object. An :term:`attached thread state` is not needed,
+ but may optionally exist if it is necessary to serialize calls to this
function.
.. audit-event:: cpython.PyInterpreterState_New "" c.PyInterpreterState_New
@@ -1365,30 +1263,28 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
.. c:function:: void PyInterpreterState_Clear(PyInterpreterState *interp)
- Reset all information in an interpreter state object. The global interpreter
- lock must be held.
+ Reset all information in an interpreter state object. There must be
+ an :term:`attached thread state` for the the interpreter.
.. audit-event:: cpython.PyInterpreterState_Clear "" c.PyInterpreterState_Clear
.. c:function:: void PyInterpreterState_Delete(PyInterpreterState *interp)
- Destroy an interpreter state object. The global interpreter lock need not be
- held. The interpreter state must have been reset with a previous call to
- :c:func:`PyInterpreterState_Clear`.
+ Destroy an interpreter state object. There **should not** be an
+ :term:`attached thread state` for the target interpreter. The interpreter
+ state must have been reset with a previous call to :c:func:`PyInterpreterState_Clear`.
.. c:function:: PyThreadState* PyThreadState_New(PyInterpreterState *interp)
Create a new thread state object belonging to the given interpreter object.
- The global interpreter lock need not be held, but may be held if it is
- necessary to serialize calls to this function.
-
+ An :term:`attached thread state` is not needed.
.. c:function:: void PyThreadState_Clear(PyThreadState *tstate)
- Reset all information in a thread state object. The global interpreter lock
- must be held.
+ Reset all information in a :term:`thread state` object. *tstate*
+ must be :term:`attached `
.. versionchanged:: 3.9
This function now calls the :c:member:`PyThreadState.on_delete` callback.
@@ -1400,18 +1296,19 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
.. c:function:: void PyThreadState_Delete(PyThreadState *tstate)
- Destroy a thread state object. The global interpreter lock need not be held.
- The thread state must have been reset with a previous call to
+ Destroy a :term:`thread state` object. *tstate* should not
+ be :term:`attached ` to any thread.
+ *tstate* must have been reset with a previous call to
:c:func:`PyThreadState_Clear`.
.. c:function:: void PyThreadState_DeleteCurrent(void)
- Destroy the current thread state and release the global interpreter lock.
- Like :c:func:`PyThreadState_Delete`, the global interpreter lock must
- be held. The thread state must have been reset with a previous call
- to :c:func:`PyThreadState_Clear`.
+ Detach the :term:`attached thread state` (which must have been reset
+ with a previous call to :c:func:`PyThreadState_Clear`) and then destroy it.
+ No :term:`thread state` will be :term:`attached ` upon
+ returning.
.. c:function:: PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
@@ -1422,16 +1319,16 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
See also :c:func:`PyEval_GetFrame`.
- *tstate* must not be ``NULL``.
+ *tstate* must not be ``NULL``, and must be :term:`attached `.
.. versionadded:: 3.9
.. c:function:: uint64_t PyThreadState_GetID(PyThreadState *tstate)
- Get the unique thread state identifier of the Python thread state *tstate*.
+ Get the unique :term:`thread state` identifier of the Python thread state *tstate*.
- *tstate* must not be ``NULL``.
+ *tstate* must not be ``NULL``, and must be :term:`attached `.
.. versionadded:: 3.9
@@ -1440,7 +1337,7 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
Get the interpreter of the Python thread state *tstate*.
- *tstate* must not be ``NULL``.
+ *tstate* must not be ``NULL``, and must be :term:`attached `.
.. versionadded:: 3.9
@@ -1469,10 +1366,8 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
Get the current interpreter.
- Issue a fatal error if there no current Python thread state or no current
- interpreter. It cannot return NULL.
-
- The caller must hold the GIL.
+ Issue a fatal error if there no :term:`attached thread state`.
+ It cannot return NULL.
.. versionadded:: 3.9
@@ -1482,7 +1377,7 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
Return the interpreter's unique ID. If there was any error in doing
so then ``-1`` is returned and an error is set.
- The caller must hold the GIL.
+ The caller must have an :term:`attached thread state`.
.. versionadded:: 3.7
@@ -1499,16 +1394,6 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
.. versionadded:: 3.8
-.. c:function:: PyObject* PyUnstable_InterpreterState_GetMainModule(PyInterpreterState *interp)
-
- Return a :term:`strong reference` to the ``__main__`` :ref:`module object `
- for the given interpreter.
-
- The caller must hold the GIL.
-
- .. versionadded:: 3.13
-
-
.. c:type:: PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag)
Type of a frame evaluation function.
@@ -1543,9 +1428,10 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
Return a dictionary in which extensions can store thread-specific state
information. Each extension should use a unique key to use to store state in
- the dictionary. It is okay to call this function when no current thread state
- is available. If this function returns ``NULL``, no exception has been raised and
- the caller should assume no current thread state is available.
+ the dictionary. It is okay to call this function when no :term:`thread state`
+ is :term:`attached `. If this function returns
+ ``NULL``, no exception has been raised and the caller should assume no
+ thread state is attached.
.. c:function:: int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
@@ -1553,7 +1439,7 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
Asynchronously raise an exception in a thread. The *id* argument is the thread
id of the target thread; *exc* is the exception object to be raised. This
function does not steal any references to *exc*. To prevent naive misuse, you
- must write your own C extension to call this. Must be called with the GIL held.
+ must write your own C extension to call this. Must be called with an :term:`attached thread state`.
Returns the number of thread states modified; this is normally one, but will be
zero if the thread id isn't found. If *exc* is ``NULL``, the pending
exception (if any) for the thread is cleared. This raises no exceptions.
@@ -1564,9 +1450,10 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
.. c:function:: void PyEval_AcquireThread(PyThreadState *tstate)
- Acquire the global interpreter lock and set the current thread state to
- *tstate*, which must not be ``NULL``. The lock must have been created earlier.
- If this thread already has the lock, deadlock ensues.
+ :term:`Attach ` *tstate* to the current thread,
+ which must not be ``NULL`` or already :term:`attached `.
+
+ The calling thread must not already have an :term:`attached thread state`.
.. note::
Calling this function from a thread when the runtime is finalizing will
@@ -1589,10 +1476,9 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
.. c:function:: void PyEval_ReleaseThread(PyThreadState *tstate)
- Reset the current thread state to ``NULL`` and release the global interpreter
- lock. The lock must have been created earlier and must be held by the current
- thread. The *tstate* argument, which must not be ``NULL``, is only used to check
- that it represents the current thread state --- if it isn't, a fatal error is
+ Detach the :term:`attached thread state`.
+ The *tstate* argument, which must not be ``NULL``, is only used to check
+ that it represents the :term:`attached thread state` --- if it isn't, a fatal error is
reported.
:c:func:`PyEval_SaveThread` is a higher-level function which is always
@@ -1732,23 +1618,23 @@ function. You can create and destroy them using the following functions:
The given *config* controls the options with which the interpreter
is initialized.
- Upon success, *tstate_p* will be set to the first thread state
- created in the new
- sub-interpreter. This thread state is made in the current thread state.
+ Upon success, *tstate_p* will be set to the first :term:`thread state`
+ created in the new sub-interpreter. This thread state is
+ :term:`attached `.
Note that no actual thread is created; see the discussion of thread states
below. If creation of the new interpreter is unsuccessful,
*tstate_p* is set to ``NULL``;
no exception is set since the exception state is stored in the
- current thread state and there may not be a current thread state.
+ :term:`attached thread state`, which might not exist.
- Like all other Python/C API functions, the global interpreter lock
- must be held before calling this function and is still held when it
- returns. Likewise a current thread state must be set on entry. On
- success, the returned thread state will be set as current. If the
- sub-interpreter is created with its own GIL then the GIL of the
- calling interpreter will be released. When the function returns,
- the new interpreter's GIL will be held by the current thread and
- the previously interpreter's GIL will remain released here.
+ Like all other Python/C API functions, an :term:`attached thread state`
+ must be present before calling this function, but it might be detached upon
+ returning. On success, the returned thread state will be :term:`attached `.
+ If the sub-interpreter is created with its own :term:`GIL` then the
+ :term:`attached thread state` of the calling interpreter will be detached.
+ When the function returns, the new interpreter's :term:`thread state`
+ will be :term:`attached ` to the current thread and
+ the previous interpreter's :term:`attached thread state` will remain detached.
.. versionadded:: 3.12
@@ -1830,13 +1716,10 @@ function. You can create and destroy them using the following functions:
.. index:: single: Py_FinalizeEx (C function)
- Destroy the (sub-)interpreter represented by the given thread state.
- The given thread state must be the current thread state. See the
- discussion of thread states below. When the call returns,
- the current thread state is ``NULL``. All thread states associated
- with this interpreter are destroyed. The global interpreter lock
- used by the target interpreter must be held before calling this
- function. No GIL is held when it returns.
+ Destroy the (sub-)interpreter represented by the given :term:`thread state`.
+ The given thread state must be :term:`attached `.
+ When the call returns, there will be no :term:`attached thread state`.
+ All thread states associated with this interpreter are destroyed.
:c:func:`Py_FinalizeEx` will destroy all sub-interpreters that
haven't been explicitly destroyed at that point.
@@ -1930,20 +1813,17 @@ pointer and a void pointer argument.
both these conditions met:
* on a :term:`bytecode` boundary;
- * with the main thread holding the :term:`global interpreter lock`
+ * with the main thread holding an :term:`attached thread state`
(*func* can therefore use the full C API).
*func* must return ``0`` on success, or ``-1`` on failure with an exception
set. *func* won't be interrupted to perform another asynchronous
notification recursively, but it can still be interrupted to switch
- threads if the global interpreter lock is released.
-
- This function doesn't need a current thread state to run, and it doesn't
- need the global interpreter lock.
+ threads if the :term:`thread state ` is detached.
- To call this function in a subinterpreter, the caller must hold the GIL.
- Otherwise, the function *func* can be scheduled to be called from the wrong
- interpreter.
+ This function doesn't need an :term:`attached thread state`. However, to call this
+ function in a subinterpreter, the caller must have an :term:`attached thread state`.
+ Otherwise, the function *func* can be scheduled to be called from the wrong interpreter.
.. warning::
This is a low-level function, only useful for very special cases.
@@ -2084,14 +1964,14 @@ Python-level trace functions in previous versions.
See also the :func:`sys.setprofile` function.
- The caller must hold the :term:`GIL`.
+ The caller must have an :term:`attached thread state`.
.. c:function:: void PyEval_SetProfileAllThreads(Py_tracefunc func, PyObject *obj)
Like :c:func:`PyEval_SetProfile` but sets the profile function in all running threads
belonging to the current interpreter instead of the setting it only on the current thread.
- The caller must hold the :term:`GIL`.
+ The caller must have an :term:`attached thread state`.
As :c:func:`PyEval_SetProfile`, this function ignores any exceptions raised while
setting the profile functions in all threads.
@@ -2110,14 +1990,14 @@ Python-level trace functions in previous versions.
See also the :func:`sys.settrace` function.
- The caller must hold the :term:`GIL`.
+ The caller must have an :term:`attached thread state`.
.. c:function:: void PyEval_SetTraceAllThreads(Py_tracefunc func, PyObject *obj)
Like :c:func:`PyEval_SetTrace` but sets the tracing function in all running threads
belonging to the current interpreter instead of the setting it only on the current thread.
- The caller must hold the :term:`GIL`.
+ The caller must have an :term:`attached thread state`.
As :c:func:`PyEval_SetTrace`, this function ignores any exceptions raised while
setting the trace functions in all threads.
@@ -2159,10 +2039,10 @@ Reference tracing
Not that tracer functions **must not** create Python objects inside or
otherwise the call will be re-entrant. The tracer also **must not** clear
- any existing exception or set an exception. The GIL will be held every time
- the tracer function is called.
+ any existing exception or set an exception. A :term:`thread state` will be active
+ every time the tracer function is called.
- The GIL must be held when calling this function.
+ There must be an :term:`attached thread state` when calling this function.
.. versionadded:: 3.13
@@ -2173,7 +2053,7 @@ Reference tracing
If no tracer was registered this function will return NULL and will set the
**data** pointer to NULL.
- The GIL must be held when calling this function.
+ There must be an :term:`attached thread state` when calling this function.
.. versionadded:: 3.13
@@ -2230,8 +2110,8 @@ CPython C level APIs are similar to those offered by pthreads and Windows:
use a thread key and functions to associate a :c:expr:`void*` value per
thread.
-The GIL does *not* need to be held when calling these functions; they supply
-their own locking.
+A :term:`thread state` does *not* need to be :term:`attached `
+when calling these functions; they suppl their own locking.
Note that :file:`Python.h` does not include the declaration of the TLS APIs,
you need to include :file:`pythread.h` to use thread-local storage.
@@ -2400,7 +2280,7 @@ The C-API provides a basic mutual exclusion lock.
Lock mutex *m*. If another thread has already locked it, the calling
thread will block until the mutex is unlocked. While blocked, the thread
- will temporarily release the :term:`GIL` if it is held.
+ will temporarily detach the :term:`thread state ` if one exists.
.. versionadded:: 3.13
diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst
index b791d3cdc5d95c..e1931655618b1c 100644
--- a/Doc/c-api/init_config.rst
+++ b/Doc/c-api/init_config.rst
@@ -320,7 +320,7 @@ Configuration Options
* - ``"cpu_count"``
- :c:member:`cpu_count `
- ``int``
- - Read-only
+ - Public
* - ``"dev_mode"``
- :c:member:`dev_mode `
- ``bool``
@@ -363,7 +363,7 @@ Configuration Options
- Read-only
* - ``"import_time"``
- :c:member:`import_time `
- - ``bool``
+ - ``int``
- Read-only
* - ``"inspect"``
- :c:member:`inspect `
@@ -505,6 +505,10 @@ Configuration Options
- :c:member:`use_hash_seed `
- ``bool``
- Read-only
+ * - ``"use_system_logger"``
+ - :c:member:`use_system_logger `
+ - ``bool``
+ - Read-only
* - ``"user_site_directory"``
- :c:member:`user_site_directory `
- ``bool``
@@ -574,8 +578,8 @@ Some options are read from the :mod:`sys` attributes. For example, the option
* ``list[str]``
* ``dict[str, str]``
- The caller must hold the GIL. The function cannot be called before
- Python initialization nor after Python finalization.
+ The caller must have an :term:`attached thread state`. The function cannot
+ be called before Python initialization nor after Python finalization.
.. versionadded:: 3.14
@@ -597,8 +601,8 @@ Some options are read from the :mod:`sys` attributes. For example, the option
* Return a new reference on success.
* Set an exception and return ``NULL`` on error.
- The caller must hold the GIL. The function cannot be called before
- Python initialization nor after Python finalization.
+ The caller must have an :term:`attached thread state`. The function cannot
+ be called before Python initialization nor after Python finalization.
.. versionadded:: 3.14
@@ -612,8 +616,10 @@ Some options are read from the :mod:`sys` attributes. For example, the option
* Raise a :exc:`ValueError` if the option is read-only (cannot be set).
* Raise a :exc:`TypeError` if *value* has not the proper type.
- The caller must hold the GIL. The function cannot be called before
- Python initialization nor after Python finalization.
+ The caller must have an :term:`attached thread state`. The function cannot
+ be called before Python initialization nor after Python finalization.
+
+ .. audit-event:: cpython.PyConfig_Set name,value c.PyConfig_Set
.. versionadded:: 3.14
@@ -1471,13 +1477,19 @@ PyConfig
.. c:member:: int import_time
- If non-zero, profile import time.
+ If ``1``, profile import time.
+ If ``2``, include additional output that indicates
+ when an imported module has already been loaded.
- Set the ``1`` by the :option:`-X importtime <-X>` option and the
+ Set by the :option:`-X importtime <-X>` option and the
:envvar:`PYTHONPROFILEIMPORTTIME` environment variable.
Default: ``0``.
+ .. versionchanged:: 3.14
+
+ Added support for ``import_time = 2``
+
.. c:member:: int inspect
Enter interactive mode after executing a script or a command.
@@ -1927,9 +1939,10 @@ PyConfig
Only available on macOS 10.12 and later, and on iOS.
- Default: ``0`` (don't use system log).
+ Default: ``0`` (don't use the system log) on macOS; ``1`` on iOS (use the
+ system log).
- .. versionadded:: 3.13.2
+ .. versionadded:: 3.14
.. c:member:: int user_site_directory
diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst
index 8ef463e3f88ca8..0c20ad17194eb6 100644
--- a/Doc/c-api/intro.rst
+++ b/Doc/c-api/intro.rst
@@ -30,6 +30,16 @@ familiar with writing an extension before attempting to embed Python in a real
application.
+Language version compatibility
+==============================
+
+Python's C API is compatible with C11 and C++11 versions of C and C++.
+
+This is a lower limit: the C API does not require features from later
+C/C++ versions.
+You do *not* need to enable your compiler's "c11 mode".
+
+
Coding standards
================
@@ -138,7 +148,7 @@ complete listing.
.. c:macro:: Py_ALWAYS_INLINE
Ask the compiler to always inline a static inline function. The compiler can
- ignore it and decides to not inline the function.
+ ignore it and decide to not inline the function.
It can be used to inline performance critical static inline functions when
building Python in debug mode with function inlining disabled. For example,
@@ -769,20 +779,11 @@ found along :envvar:`PATH`.) The user can override this behavior by setting the
environment variable :envvar:`PYTHONHOME`, or insert additional directories in
front of the standard path by setting :envvar:`PYTHONPATH`.
-.. index::
- single: Py_GetPath (C function)
- single: Py_GetPrefix (C function)
- single: Py_GetExecPrefix (C function)
- single: Py_GetProgramFullPath (C function)
-
The embedding application can steer the search by setting
:c:member:`PyConfig.program_name` *before* calling
:c:func:`Py_InitializeFromConfig`. Note that
:envvar:`PYTHONHOME` still overrides this and :envvar:`PYTHONPATH` is still
-inserted in front of the standard path. An application that requires total
-control has to provide its own implementation of :c:func:`Py_GetPath`,
-:c:func:`Py_GetPrefix`, :c:func:`Py_GetExecPrefix`, and
-:c:func:`Py_GetProgramFullPath` (all defined in :file:`Modules/getpath.c`).
+inserted in front of the standard path.
.. index:: single: Py_IsInitialized (C function)
@@ -816,14 +817,17 @@ frequently used builds will be described in the remainder of this section.
Compiling the interpreter with the :c:macro:`!Py_DEBUG` macro defined produces
what is generally meant by :ref:`a debug build of Python `.
-:c:macro:`!Py_DEBUG` is enabled in the Unix build by adding
-:option:`--with-pydebug` to the :file:`./configure` command.
-It is also implied by the presence of the
-not-Python-specific :c:macro:`!_DEBUG` macro. When :c:macro:`!Py_DEBUG` is enabled
-in the Unix build, compiler optimization is disabled.
+
+On Unix, :c:macro:`!Py_DEBUG` can be enabled by adding :option:`--with-pydebug`
+to the :file:`./configure` command. This will also disable compiler optimization.
+
+On Windows, selecting a debug build (e.g., by passing the :option:`-d` option to
+:file:`PCbuild/build.bat`) automatically enables :c:macro:`!Py_DEBUG`.
+Additionally, the presence of the not-Python-specific :c:macro:`!_DEBUG` macro,
+when defined by the compiler, will also implicitly enable :c:macro:`!Py_DEBUG`.
In addition to the reference count debugging described below, extra checks are
-performed, see :ref:`Python Debug Build `.
+performed. See :ref:`Python Debug Build ` for more details.
Defining :c:macro:`Py_TRACE_REFS` enables reference tracing
(see the :option:`configure --with-trace-refs option <--with-trace-refs>`).
diff --git a/Doc/c-api/lifecycle.dot b/Doc/c-api/lifecycle.dot
new file mode 100644
index 00000000000000..dca9f87e9e0aca
--- /dev/null
+++ b/Doc/c-api/lifecycle.dot
@@ -0,0 +1,156 @@
+digraph "Life Events" {
+ graph [
+ fontnames="svg"
+ fontsize=12.0
+ id="life_events_graph"
+ layout="dot"
+ margin="0,0"
+ ranksep=0.25
+ stylesheet="lifecycle.dot.css"
+ ]
+ node [
+ fontname="Courier"
+ fontsize=12.0
+ ]
+ edge [
+ fontname="Times-Italic"
+ fontsize=12.0
+ ]
+
+ "start" [fontname="Times-Italic" shape=plain label=< start > style=invis]
+ {
+ rank="same"
+ "tp_new" [href="typeobj.html#c.PyTypeObject.tp_new" target="_top"]
+ "tp_alloc" [href="typeobj.html#c.PyTypeObject.tp_alloc" target="_top"]
+ }
+ "tp_init" [href="typeobj.html#c.PyTypeObject.tp_init" target="_top"]
+ "reachable" [fontname="Times-Italic" shape=box]
+ "tp_traverse" [
+ href="typeobj.html#c.PyTypeObject.tp_traverse"
+ ordering="in"
+ target="_top"
+ ]
+ "finalized?" [
+ fontname="Times-Italic"
+ label=finalized?>
+ ordering="in"
+ shape=diamond
+ tooltip="marked as finalized?"
+ ]
+ "tp_finalize" [
+ href="typeobj.html#c.PyTypeObject.tp_finalize"
+ ordering="in"
+ target="_top"
+ ]
+ "tp_clear" [href="typeobj.html#c.PyTypeObject.tp_clear" target="_top"]
+ "uncollectable" [
+ fontname="Times-Italic"
+ label=(leaked)>
+ shape=box
+ tooltip="uncollectable (leaked)"
+ ]
+ "tp_dealloc" [
+ href="typeobj.html#c.PyTypeObject.tp_dealloc"
+ ordering="in"
+ target="_top"
+ ]
+ "tp_free" [href="typeobj.html#c.PyTypeObject.tp_free" target="_top"]
+
+ "start" -> "tp_new" [
+ label=< type call >
+ ]
+ "tp_new" -> "tp_alloc" [
+ label=< direct call > arrowhead=empty
+ labeltooltip="tp_new to tp_alloc: direct call"
+ tooltip="tp_new to tp_alloc: direct call"
+ ]
+ "tp_new" -> "tp_init" [tooltip="tp_new to tp_init"]
+ "tp_init" -> "reachable" [tooltip="tp_init to reachable"]
+ "reachable" -> "tp_traverse" [
+ dir="back"
+ label=< not in a cyclic isolate >
+ labeltooltip="tp_traverse to reachable: not in a cyclic isolate"
+ tooltip="tp_traverse to reachable: not in a cyclic isolate"
+ ]
+ "reachable" -> "tp_traverse" [
+ label=< periodic cyclic isolate detection >
+ labeltooltip="reachable to tp_traverse: periodic cyclic isolate detection"
+ tooltip="reachable to tp_traverse: periodic cyclic isolate detection"
+ ]
+ "reachable" -> "tp_init" [tooltip="reachable to tp_init"]
+ "reachable" -> "tp_finalize" [
+ dir="back"
+ label=< resurrected (maybe remove finalized mark) >
+ labeltooltip="tp_finalize to reachable: resurrected (maybe remove finalized mark)"
+ tooltip="tp_finalize to reachable: resurrected (maybe remove finalized mark)"
+ ]
+ "tp_traverse" -> "finalized?" [
+ label=< cyclic isolate >
+ labeltooltip="tp_traverse to finalized?: cyclic isolate"
+ tooltip="tp_traverse to finalized?: cyclic isolate"
+ ]
+ "reachable" -> "finalized?" [
+ label=< no refs >
+ labeltooltip="reachable to finalized?: no refs"
+ tooltip="reachable to finalized?: no refs"
+ ]
+ "finalized?" -> "tp_finalize" [
+ label=< no (mark as finalized) >
+ labeltooltip="finalized? to tp_finalize: no (mark as finalized)"
+ tooltip="finalized? to tp_finalize: no (mark as finalized)"
+ ]
+ "finalized?" -> "tp_clear" [
+ label=< yes >
+ labeltooltip="finalized? to tp_clear: yes"
+ tooltip="finalized? to tp_clear: yes"
+ ]
+ "tp_finalize" -> "tp_clear" [
+ label=< no refs or cyclic isolate >
+ labeltooltip="tp_finalize to tp_clear: no refs or cyclic isolate"
+ tooltip="tp_finalize to tp_clear: no refs or cyclic isolate"
+ ]
+ "tp_finalize" -> "tp_dealloc" [
+ arrowtail=empty
+ dir="back"
+ href="lifecycle.html#c.PyObject_CallFinalizerFromDealloc"
+ style=dashed
+ label=< recommended call (see explanation)>
+ labeltooltip="tp_dealloc to tp_finalize: recommended call (see explanation)"
+ target="_top"
+ tooltip="tp_dealloc to tp_finalize: recommended call (see explanation)"
+ ]
+ "tp_finalize" -> "tp_dealloc" [
+ label=< no refs >
+ labeltooltip="tp_finalize to tp_dealloc: no refs"
+ tooltip="tp_finalize to tp_dealloc: no refs"
+ ]
+ "tp_clear" -> "tp_dealloc" [
+ label=< no refs >
+ labeltooltip="tp_clear to tp_dealloc: no refs"
+ tooltip="tp_clear to tp_dealloc: no refs"
+ ]
+ "tp_clear" -> "uncollectable" [
+ label=< cyclic isolate >
+ labeltooltip="tp_clear to uncollectable: cyclic isolate"
+ tooltip="tp_clear to uncollectable: cyclic isolate"
+ ]
+ "uncollectable" -> "tp_dealloc" [
+ style=invis
+ tooltip="uncollectable to tp_dealloc"
+ ]
+ "reachable" -> "uncollectable" [
+ label=< cyclic isolate (no GC support) >
+ labeltooltip="reachable to uncollectable: cyclic isolate (no GC support)"
+ tooltip="reachable to uncollectable: cyclic isolate (no GC support)"
+ ]
+ "reachable" -> "tp_dealloc" [
+ label=< no refs>
+ labeltooltip="reachable to tp_dealloc: no refs"
+ ]
+ "tp_dealloc" -> "tp_free" [
+ arrowhead=empty
+ label=< direct call >
+ labeltooltip="tp_dealloc to tp_free: direct call"
+ tooltip="tp_dealloc to tp_free: direct call"
+ ]
+}
diff --git a/Doc/c-api/lifecycle.dot.css b/Doc/c-api/lifecycle.dot.css
new file mode 100644
index 00000000000000..3abf95b74da6ba
--- /dev/null
+++ b/Doc/c-api/lifecycle.dot.css
@@ -0,0 +1,21 @@
+#life_events_graph {
+ --svg-fgcolor: currentcolor;
+ --svg-bgcolor: transparent;
+}
+#life_events_graph a {
+ color: inherit;
+}
+#life_events_graph [stroke="black"] {
+ stroke: var(--svg-fgcolor);
+}
+#life_events_graph text,
+#life_events_graph [fill="black"] {
+ fill: var(--svg-fgcolor);
+}
+#life_events_graph [fill="white"] {
+ fill: var(--svg-bgcolor);
+}
+#life_events_graph [fill="none"] {
+ /* On links, setting fill will make the entire shape clickable */
+ fill: var(--svg-bgcolor);
+}
diff --git a/Doc/c-api/lifecycle.dot.pdf b/Doc/c-api/lifecycle.dot.pdf
new file mode 100644
index 00000000000000..ed5b5039c83e2c
Binary files /dev/null and b/Doc/c-api/lifecycle.dot.pdf differ
diff --git a/Doc/c-api/lifecycle.dot.svg b/Doc/c-api/lifecycle.dot.svg
new file mode 100644
index 00000000000000..7ace27dfcba113
--- /dev/null
+++ b/Doc/c-api/lifecycle.dot.svg
@@ -0,0 +1,374 @@
+
+
+
+
+
+
diff --git a/Doc/c-api/lifecycle.rst b/Doc/c-api/lifecycle.rst
new file mode 100644
index 00000000000000..0e2ffc096caba7
--- /dev/null
+++ b/Doc/c-api/lifecycle.rst
@@ -0,0 +1,273 @@
+.. highlight:: c
+
+.. _life-cycle:
+
+Object Life Cycle
+=================
+
+This section explains how a type's slots relate to each other throughout the
+life of an object. It is not intended to be a complete canonical reference for
+the slots; instead, refer to the slot-specific documentation in
+:ref:`type-structs` for details about a particular slot.
+
+
+Life Events
+-----------
+
+The figure below illustrates the order of events that can occur throughout an
+object's life. An arrow from *A* to *B* indicates that event *B* can occur
+after event *A* has occurred, with the arrow's label indicating the condition
+that must be true for *B* to occur after *A*.
+
+.. only:: html and not epub
+
+ .. raw:: html
+
+
+
+ .. raw:: html
+ :file: lifecycle.dot.svg
+
+ .. raw:: html
+
+
+
+.. only:: epub or not (html or latex)
+
+ .. image:: lifecycle.dot.svg
+ :align: center
+ :class: invert-in-dark-mode
+ :alt: Diagram showing events in an object's life. Explained in detail
+ below.
+
+.. only:: latex
+
+ .. image:: lifecycle.dot.pdf
+ :align: center
+ :class: invert-in-dark-mode
+ :alt: Diagram showing events in an object's life. Explained in detail
+ below.
+
+.. container::
+ :name: life-events-graph-description
+
+ Explanation:
+
+ * When a new object is constructed by calling its type:
+
+ #. :c:member:`~PyTypeObject.tp_new` is called to create a new object.
+ #. :c:member:`~PyTypeObject.tp_alloc` is directly called by
+ :c:member:`~PyTypeObject.tp_new` to allocate the memory for the new
+ object.
+ #. :c:member:`~PyTypeObject.tp_init` initializes the newly created object.
+ :c:member:`!tp_init` can be called again to re-initialize an object, if
+ desired. The :c:member:`!tp_init` call can also be skipped entirely,
+ for example by Python code calling :py:meth:`~object.__new__`.
+
+ * After :c:member:`!tp_init` completes, the object is ready to use.
+ * Some time after the last reference to an object is removed:
+
+ #. If an object is not marked as *finalized*, it might be finalized by
+ marking it as *finalized* and calling its
+ :c:member:`~PyTypeObject.tp_finalize` function. Python does
+ *not* finalize an object when the last reference to it is deleted; use
+ :c:func:`PyObject_CallFinalizerFromDealloc` to ensure that
+ :c:member:`~PyTypeObject.tp_finalize` is always called.
+ #. If the object is marked as finalized,
+ :c:member:`~PyTypeObject.tp_clear` might be called by the garbage collector
+ to clear references held by the object. It is *not* called when the
+ object's reference count reaches zero.
+ #. :c:member:`~PyTypeObject.tp_dealloc` is called to destroy the object.
+ To avoid code duplication, :c:member:`~PyTypeObject.tp_dealloc` typically
+ calls into :c:member:`~PyTypeObject.tp_clear` to free up the object's
+ references.
+ #. When :c:member:`~PyTypeObject.tp_dealloc` finishes object destruction,
+ it directly calls :c:member:`~PyTypeObject.tp_free` (usually set to
+ :c:func:`PyObject_Free` or :c:func:`PyObject_GC_Del` automatically as
+ appropriate for the type) to deallocate the memory.
+
+ * The :c:member:`~PyTypeObject.tp_finalize` function is permitted to add a
+ reference to the object if desired. If it does, the object is
+ *resurrected*, preventing its pending destruction. (Only
+ :c:member:`!tp_finalize` is allowed to resurrect an object;
+ :c:member:`~PyTypeObject.tp_clear` and
+ :c:member:`~PyTypeObject.tp_dealloc` cannot without calling into
+ :c:member:`!tp_finalize`.) Resurrecting an object may
+ or may not cause the object's *finalized* mark to be removed. Currently,
+ Python does not remove the *finalized* mark from a resurrected object if
+ it supports garbage collection (i.e., the :c:macro:`Py_TPFLAGS_HAVE_GC`
+ flag is set) but does remove the mark if the object does not support
+ garbage collection; either or both of these behaviors may change in the
+ future.
+ * :c:member:`~PyTypeObject.tp_dealloc` can optionally call
+ :c:member:`~PyTypeObject.tp_finalize` via
+ :c:func:`PyObject_CallFinalizerFromDealloc` if it wishes to reuse that
+ code to help with object destruction. This is recommended because it
+ guarantees that :c:member:`!tp_finalize` is always called before
+ destruction. See the :c:member:`~PyTypeObject.tp_dealloc` documentation
+ for example code.
+ * If the object is a member of a :term:`cyclic isolate` and either
+ :c:member:`~PyTypeObject.tp_clear` fails to break the reference cycle or
+ the cyclic isolate is not detected (perhaps :func:`gc.disable` was called,
+ or the :c:macro:`Py_TPFLAGS_HAVE_GC` flag was erroneously omitted in one
+ of the involved types), the objects remain indefinitely uncollectable
+ (they "leak"). See :data:`gc.garbage`.
+
+ If the object is marked as supporting garbage collection (the
+ :c:macro:`Py_TPFLAGS_HAVE_GC` flag is set in
+ :c:member:`~PyTypeObject.tp_flags`), the following events are also possible:
+
+ * The garbage collector occasionally calls
+ :c:member:`~PyTypeObject.tp_traverse` to identify :term:`cyclic isolates
+ `.
+ * When the garbage collector discovers a :term:`cyclic isolate`, it
+ finalizes one of the objects in the group by marking it as *finalized* and
+ calling its :c:member:`~PyTypeObject.tp_finalize` function, if it has one.
+ This repeats until the cyclic isolate doesn't exist or all of the objects
+ have been finalized.
+ * :c:member:`~PyTypeObject.tp_finalize` is permitted to resurrect the object
+ by adding a reference from outside the :term:`cyclic isolate`. The new
+ reference causes the group of objects to no longer form a cyclic isolate
+ (the reference cycle may still exist, but if it does the objects are no
+ longer isolated).
+ * When the garbage collector discovers a :term:`cyclic isolate` and all of
+ the objects in the group have already been marked as *finalized*, the
+ garbage collector clears one or more of the uncleared objects in the group
+ (possibly concurrently) by calling each's
+ :c:member:`~PyTypeObject.tp_clear` function. This repeats as long as the
+ cyclic isolate still exists and not all of the objects have been cleared.
+
+
+Cyclic Isolate Destruction
+--------------------------
+
+Listed below are the stages of life of a hypothetical :term:`cyclic isolate`
+that continues to exist after each member object is finalized or cleared. It
+is a memory leak if a cyclic isolate progresses through all of these stages; it should
+vanish once all objects are cleared, if not sooner. A cyclic isolate can
+vanish either because the reference cycle is broken or because the objects are
+no longer isolated due to finalizer resurrection (see
+:c:member:`~PyTypeObject.tp_finalize`).
+
+0. **Reachable** (not yet a cyclic isolate): All objects are in their normal,
+ reachable state. A reference cycle could exist, but an external reference
+ means the objects are not yet isolated.
+#. **Unreachable but consistent:** The final reference from outside the cyclic
+ group of objects has been removed, causing the objects to become isolated
+ (thus a cyclic isolate is born). None of the group's objects have been
+ finalized or cleared yet. The cyclic isolate remains at this stage until
+ some future run of the garbage collector (not necessarily the next run
+ because the next run might not scan every object).
+#. **Mix of finalized and not finalized:** Objects in a cyclic isolate are
+ finalized one at a time, which means that there is a period of time when the
+ cyclic isolate is composed of a mix of finalized and non-finalized objects.
+ Finalization order is unspecified, so it can appear random. A finalized
+ object must behave in a sane manner when non-finalized objects interact with
+ it, and a non-finalized object must be able to tolerate the finalization of
+ an arbitrary subset of its referents.
+#. **All finalized:** All objects in a cyclic isolate are finalized before any
+ of them are cleared.
+#. **Mix of finalized and cleared:** The objects can be cleared serially or
+ concurrently (but with the :term:`GIL` held); either way, some will finish
+ before others. A finalized object must be able to tolerate the clearing of
+ a subset of its referents. :pep:`442` calls this stage "cyclic trash".
+#. **Leaked:** If a cyclic isolate still exists after all objects in the group
+ have been finalized and cleared, then the objects remain indefinitely
+ uncollectable (see :data:`gc.garbage`). It is a bug if a cyclic isolate
+ reaches this stage---it means the :c:member:`~PyTypeObject.tp_clear` methods
+ of the participating objects have failed to break the reference cycle as
+ required.
+
+If :c:member:`~PyTypeObject.tp_clear` did not exist, then Python would have no
+way to safely break a reference cycle. Simply destroying an object in a cyclic
+isolate would result in a dangling pointer, triggering undefined behavior when
+an object referencing the destroyed object is itself destroyed. The clearing
+step makes object destruction a two-phase process: first
+:c:member:`~PyTypeObject.tp_clear` is called to partially destroy the objects
+enough to detangle them from each other, then
+:c:member:`~PyTypeObject.tp_dealloc` is called to complete the destruction.
+
+Unlike clearing, finalization is not a phase of destruction. A finalized
+object must still behave properly by continuing to fulfill its design
+contracts. An object's finalizer is allowed to execute arbitrary Python code,
+and is even allowed to prevent the impending destruction by adding a reference.
+The finalizer is only related to destruction by call order---if it runs, it runs
+before destruction, which starts with :c:member:`~PyTypeObject.tp_clear` (if
+called) and concludes with :c:member:`~PyTypeObject.tp_dealloc`.
+
+The finalization step is not necessary to safely reclaim the objects in a
+cyclic isolate, but its existence makes it easier to design types that behave
+in a sane manner when objects are cleared. Clearing an object might
+necessarily leave it in a broken, partially destroyed state---it might be
+unsafe to call any of the cleared object's methods or access any of its
+attributes. With finalization, only finalized objects can possibly interact
+with cleared objects; non-finalized objects are guaranteed to interact with
+only non-cleared (but potentially finalized) objects.
+
+To summarize the possible interactions:
+
+* A non-finalized object might have references to or from non-finalized and
+ finalized objects, but not to or from cleared objects.
+* A finalized object might have references to or from non-finalized, finalized,
+ and cleared objects.
+* A cleared object might have references to or from finalized and cleared
+ objects, but not to or from non-finalized objects.
+
+Without any reference cycles, an object can be simply destroyed once its last
+reference is deleted; the finalization and clearing steps are not necessary to
+safely reclaim unused objects. However, it can be useful to automatically call
+:c:member:`~PyTypeObject.tp_finalize` and :c:member:`~PyTypeObject.tp_clear`
+before destruction anyway because type design is simplified when all objects
+always experience the same series of events regardless of whether they
+participated in a cyclic isolate. Python currently only calls
+:c:member:`~PyTypeObject.tp_finalize` and :c:member:`~PyTypeObject.tp_clear` as
+needed to destroy a cyclic isolate; this may change in a future version.
+
+
+Functions
+---------
+
+To allocate and free memory, see :ref:`allocating-objects`.
+
+
+.. c:function:: void PyObject_CallFinalizer(PyObject *op)
+
+ Finalizes the object as described in :c:member:`~PyTypeObject.tp_finalize`.
+ Call this function (or :c:func:`PyObject_CallFinalizerFromDealloc`) instead
+ of calling :c:member:`~PyTypeObject.tp_finalize` directly because this
+ function may deduplicate multiple calls to :c:member:`!tp_finalize`.
+ Currently, calls are only deduplicated if the type supports garbage
+ collection (i.e., the :c:macro:`Py_TPFLAGS_HAVE_GC` flag is set); this may
+ change in the future.
+
+
+.. c:function:: int PyObject_CallFinalizerFromDealloc(PyObject *op)
+
+ Same as :c:func:`PyObject_CallFinalizer` but meant to be called at the
+ beginning of the object's destructor (:c:member:`~PyTypeObject.tp_dealloc`).
+ There must not be any references to the object. If the object's finalizer
+ resurrects the object, this function returns -1; no further destruction
+ should happen. Otherwise, this function returns 0 and destruction can
+ continue normally.
+
+ .. seealso::
+
+ :c:member:`~PyTypeObject.tp_dealloc` for example code.
diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst
index aa2ef499bddaf3..61fa49f8681cce 100644
--- a/Doc/c-api/memory.rst
+++ b/Doc/c-api/memory.rst
@@ -110,12 +110,12 @@ The three allocation domains are:
* Raw domain: intended for allocating memory for general-purpose memory
buffers where the allocation *must* go to the system allocator or where the
- allocator can operate without the :term:`GIL`. The memory is requested directly
- from the system. See :ref:`Raw Memory Interface `.
+ allocator can operate without an :term:`attached thread state`. The memory
+ is requested directly from the system. See :ref:`Raw Memory Interface `.
* "Mem" domain: intended for allocating memory for Python buffers and
general-purpose memory buffers where the allocation must be performed with
- the :term:`GIL` held. The memory is taken from the Python private heap.
+ an :term:`attached thread state`. The memory is taken from the Python private heap.
See :ref:`Memory Interface `.
* Object domain: intended for allocating memory for Python objects. The
@@ -139,8 +139,8 @@ Raw Memory Interface
====================
The following function sets are wrappers to the system allocator. These
-functions are thread-safe, the :term:`GIL ` does not
-need to be held.
+functions are thread-safe, so a :term:`thread state` does not
+need to be :term:`attached `.
The :ref:`default raw memory allocator ` uses
the following functions: :c:func:`malloc`, :c:func:`calloc`, :c:func:`realloc`
@@ -213,8 +213,7 @@ The :ref:`default memory allocator ` uses the
.. warning::
- The :term:`GIL ` must be held when using these
- functions.
+ There must be an :term:`attached thread state` when using these functions.
.. versionchanged:: 3.6
@@ -327,8 +326,7 @@ The :ref:`default object allocator ` uses the
.. warning::
- The :term:`GIL ` must be held when using these
- functions.
+ There must be an :term:`attached thread state` when using these functions.
.. c:function:: void* PyObject_Malloc(size_t n)
@@ -378,6 +376,24 @@ The :ref:`default object allocator ` uses the
If *p* is ``NULL``, no operation is performed.
+ Do not call this directly to free an object's memory; call the type's
+ :c:member:`~PyTypeObject.tp_free` slot instead.
+
+ Do not use this for memory allocated by :c:macro:`PyObject_GC_New` or
+ :c:macro:`PyObject_GC_NewVar`; use :c:func:`PyObject_GC_Del` instead.
+
+ .. seealso::
+
+ * :c:func:`PyObject_GC_Del` is the equivalent of this function for memory
+ allocated by types that support garbage collection.
+ * :c:func:`PyObject_Malloc`
+ * :c:func:`PyObject_Realloc`
+ * :c:func:`PyObject_Calloc`
+ * :c:macro:`PyObject_New`
+ * :c:macro:`PyObject_NewVar`
+ * :c:func:`PyType_GenericAlloc`
+ * :c:member:`~PyTypeObject.tp_free`
+
.. _default-memory-allocators:
@@ -485,12 +501,12 @@ Customize Memory Allocators
zero bytes.
For the :c:macro:`PYMEM_DOMAIN_RAW` domain, the allocator must be
- thread-safe: the :term:`GIL ` is not held when the
- allocator is called.
+ thread-safe: a :term:`thread state` is not :term:`attached `
+ when the allocator is called.
For the remaining domains, the allocator must also be thread-safe:
the allocator may be called in different interpreters that do not
- share a ``GIL``.
+ share a :term:`GIL`.
If the new allocator is not a hook (does not call the previous allocator),
the :c:func:`PyMem_SetupDebugHooks` function must be called to reinstall the
@@ -507,8 +523,8 @@ Customize Memory Allocators
:c:func:`Py_InitializeFromConfig` to install a custom memory
allocator. There are no restrictions over the installed allocator
other than the ones imposed by the domain (for instance, the Raw
- Domain allows the allocator to be called without the GIL held). See
- :ref:`the section on allocator domains ` for more
+ Domain allows the allocator to be called without an :term:`attached thread state`).
+ See :ref:`the section on allocator domains ` for more
information.
* If called after Python has finish initializing (after
@@ -555,7 +571,7 @@ Runtime checks:
called on a memory block allocated by :c:func:`PyMem_Malloc`.
- Detect write before the start of the buffer (buffer underflow).
- Detect write after the end of the buffer (buffer overflow).
-- Check that the :term:`GIL ` is held when
+- Check that there is an :term:`attached thread state` when
allocator functions of :c:macro:`PYMEM_DOMAIN_OBJ` (ex:
:c:func:`PyObject_Malloc`) and :c:macro:`PYMEM_DOMAIN_MEM` (ex:
:c:func:`PyMem_Malloc`) domains are called.
@@ -620,8 +636,8 @@ PYMEM_CLEANBYTE (meaning uninitialized memory is getting used).
The :c:func:`PyMem_SetupDebugHooks` function now also works on Python
compiled in release mode. On error, the debug hooks now use
:mod:`tracemalloc` to get the traceback where a memory block was allocated.
- The debug hooks now also check if the GIL is held when functions of
- :c:macro:`PYMEM_DOMAIN_OBJ` and :c:macro:`PYMEM_DOMAIN_MEM` domains are
+ The debug hooks now also check if there is an :term:`attached thread state` when
+ functions of :c:macro:`PYMEM_DOMAIN_OBJ` and :c:macro:`PYMEM_DOMAIN_MEM` domains are
called.
.. versionchanged:: 3.8
diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst
index f71089370152ce..f7f4d37d4c721f 100644
--- a/Doc/c-api/module.rst
+++ b/Doc/c-api/module.rst
@@ -415,7 +415,7 @@ The available slot types are:
in one module definition.
If ``Py_mod_multiple_interpreters`` is not specified, the import
- machinery defaults to ``Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED``.
+ machinery defaults to ``Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED``.
.. versionadded:: 3.12
@@ -709,7 +709,7 @@ since multiple such modules can be created from a single definition.
mechanisms (either by calling it directly, or by referring to its
implementation for details of the required state updates).
- The caller must hold the GIL.
+ The caller must have an :term:`attached thread state`.
Return ``-1`` with an exception set on error, ``0`` on success.
@@ -720,6 +720,6 @@ since multiple such modules can be created from a single definition.
Removes the module object created from *def* from the interpreter state.
Return ``-1`` with an exception set on error, ``0`` on success.
- The caller must hold the GIL.
+ The caller must have an :term:`attached thread state`.
.. versionadded:: 3.3
diff --git a/Doc/c-api/monitoring.rst b/Doc/c-api/monitoring.rst
index bda6cd271197d0..7926148302af0b 100644
--- a/Doc/c-api/monitoring.rst
+++ b/Doc/c-api/monitoring.rst
@@ -196,3 +196,15 @@ would typically correspond to a python function.
.. c:function:: int PyMonitoring_ExitScope(void)
Exit the last scope that was entered with :c:func:`!PyMonitoring_EnterScope`.
+
+
+.. c:function:: int PY_MONITORING_IS_INSTRUMENTED_EVENT(uint8_t ev)
+
+ Return true if the event corresponding to the event ID *ev* is
+ a :ref:`local event `.
+
+ .. versionadded:: 3.13
+
+ .. deprecated:: 3.14
+
+ This function is :term:`soft deprecated`.
diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst
index bef3a79ccd0e21..0fd159f1eb87f8 100644
--- a/Doc/c-api/object.rst
+++ b/Doc/c-api/object.rst
@@ -613,6 +613,38 @@ Object Protocol
.. versionadded:: 3.14
+.. c:function:: int PyUnstable_Object_IsUniqueReferencedTemporary(PyObject *obj)
+
+ Check if *obj* is a unique temporary object.
+ Returns ``1`` if *obj* is known to be a unique temporary object,
+ and ``0`` otherwise. This function cannot fail, but the check is
+ conservative, and may return ``0`` in some cases even if *obj* is a unique
+ temporary object.
+
+ If an object is a unique temporary, it is guaranteed that the current code
+ has the only reference to the object. For arguments to C functions, this
+ should be used instead of checking if the reference count is ``1``. Starting
+ with Python 3.14, the interpreter internally avoids some reference count
+ modifications when loading objects onto the operands stack by
+ :term:`borrowing ` references when possible, which means
+ that a reference count of ``1`` by itself does not guarantee that a function
+ argument uniquely referenced.
+
+ In the example below, ``my_func`` is called with a unique temporary object
+ as its argument::
+
+ my_func([1, 2, 3])
+
+ In the example below, ``my_func`` is **not** called with a unique temporary
+ object as its argument, even if its refcount is ``1``::
+
+ my_list = [1, 2, 3]
+ my_func(my_list)
+
+ See also the function :c:func:`Py_REFCNT`.
+
+ .. versionadded:: 3.14
+
.. c:function:: int PyUnstable_IsImmortal(PyObject *obj)
This function returns non-zero if *obj* is :term:`immortal`, and zero
@@ -705,3 +737,21 @@ Object Protocol
caller must hold a :term:`strong reference` to *obj* when calling this.
.. versionadded:: 3.14
+
+.. c:function:: int PyUnstable_Object_IsUniquelyReferenced(PyObject *op)
+
+ Determine if *op* only has one reference.
+
+ On GIL-enabled builds, this function is equivalent to
+ :c:expr:`Py_REFCNT(op) == 1`.
+
+ On a :term:`free threaded ` build, this checks if *op*'s
+ :term:`reference count` is equal to one and additionally checks if *op*
+ is only used by this thread. :c:expr:`Py_REFCNT(op) == 1` is **not**
+ thread-safe on free threaded builds; prefer this function.
+
+ The caller must hold an :term:`attached thread state`, despite the fact
+ that this function doesn't call into the Python interpreter. This function
+ cannot fail.
+
+ .. versionadded:: 3.14
diff --git a/Doc/c-api/objimpl.rst b/Doc/c-api/objimpl.rst
index 8bd8c107c98bdf..83de4248039949 100644
--- a/Doc/c-api/objimpl.rst
+++ b/Doc/c-api/objimpl.rst
@@ -12,6 +12,7 @@ object types.
.. toctree::
allocation.rst
+ lifecycle.rst
structures.rst
typeobj.rst
gcsupport.rst
diff --git a/Doc/c-api/perfmaps.rst b/Doc/c-api/perfmaps.rst
index 3d44d2eb6bf41d..77b5e3c0876bbb 100644
--- a/Doc/c-api/perfmaps.rst
+++ b/Doc/c-api/perfmaps.rst
@@ -16,7 +16,7 @@ kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jit-interface.txt>`_
In Python, these helper APIs can be used by libraries and features that rely
on generating machine code on the fly.
-Note that holding the Global Interpreter Lock (GIL) is not required for these APIs.
+Note that holding an :term:`attached thread state` is not required for these APIs.
.. c:function:: int PyUnstable_PerfMapState_Init(void)
diff --git a/Doc/c-api/refcounting.rst b/Doc/c-api/refcounting.rst
index d75dad737bc992..b23f016f9b0a06 100644
--- a/Doc/c-api/refcounting.rst
+++ b/Doc/c-api/refcounting.rst
@@ -23,6 +23,15 @@ of Python objects.
Use the :c:func:`Py_SET_REFCNT()` function to set an object reference count.
+ .. note::
+
+ On :term:`free threaded ` builds of Python, returning 1
+ isn't sufficient to determine if it's safe to treat *o* as having no
+ access by other threads. Use :c:func:`PyUnstable_Object_IsUniquelyReferenced`
+ for that instead.
+
+ See also the function :c:func:`PyUnstable_Object_IsUniqueReferencedTemporary()`.
+
.. versionchanged:: 3.10
:c:func:`Py_REFCNT()` is changed to the inline static function.
diff --git a/Doc/c-api/reflection.rst b/Doc/c-api/reflection.rst
index 038e6977104560..54fd5a064aa2ac 100644
--- a/Doc/c-api/reflection.rst
+++ b/Doc/c-api/reflection.rst
@@ -55,7 +55,7 @@ Reflection
.. c:function:: PyFrameObject* PyEval_GetFrame(void)
- Return the current thread state's frame, which is ``NULL`` if no frame is
+ Return the :term:`attached thread state`'s frame, which is ``NULL`` if no frame is
currently executing.
See also :c:func:`PyThreadState_GetFrame`.
diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst
index d333df397782e0..987bc167c68d6c 100644
--- a/Doc/c-api/structures.rst
+++ b/Doc/c-api/structures.rst
@@ -63,6 +63,11 @@ under :ref:`reference counting `.
See documentation of :c:type:`PyVarObject` above.
+.. c:var:: PyTypeObject PyBaseObject_Type
+
+ The base class of all other objects, the same as :class:`object` in Python.
+
+
.. c:function:: int Py_Is(PyObject *x, PyObject *y)
Test if the *x* object is the *y* object, the same as ``x is y`` in Python.
diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst
index 4ab5df4ccccdbb..b3c89800e386ff 100644
--- a/Doc/c-api/sys.rst
+++ b/Doc/c-api/sys.rst
@@ -232,7 +232,7 @@ Operating System Utilities
The file descriptor is created non-inheritable (:pep:`446`).
- The caller must hold the GIL.
+ The caller must have an :term:`attached thread state`.
.. versionadded:: 3.14
@@ -378,8 +378,8 @@ accessible to C code. They all work with the current interpreter thread's
silently abort the operation by raising an error subclassed from
:class:`Exception` (other errors will not be silenced).
- The hook function is always called with the GIL held by the Python
- interpreter that raised the event.
+ The hook function is always called with an :term:`attached thread state` by
+ the Python interpreter that raised the event.
See :pep:`578` for a detailed description of auditing. Functions in the
runtime and standard library that raise events are listed in the
diff --git a/Doc/c-api/time.rst b/Doc/c-api/time.rst
index 7032cc48aa6913..31d6adbc225439 100644
--- a/Doc/c-api/time.rst
+++ b/Doc/c-api/time.rst
@@ -56,7 +56,7 @@ range.
system time.)
As any other C API (unless otherwise specified), the functions must be called
-with the :term:`GIL` held.
+with an :term:`attached thread state`.
.. c:function:: int PyTime_Monotonic(PyTime_t *result)
@@ -78,29 +78,29 @@ Raw Clock Functions
-------------------
Similar to clock functions, but don't set an exception on error and don't
-require the caller to hold the GIL.
+require the caller to have an :term:`attached thread state`.
On success, the functions return ``0``.
On failure, they set ``*result`` to ``0`` and return ``-1``, *without* setting
-an exception. To get the cause of the error, acquire the GIL and call the
-regular (non-``Raw``) function. Note that the regular function may succeed after
+an exception. To get the cause of the error, :term:`attach ` a :term:`thread state`,
+and call the regular (non-``Raw``) function. Note that the regular function may succeed after
the ``Raw`` one failed.
.. c:function:: int PyTime_MonotonicRaw(PyTime_t *result)
Similar to :c:func:`PyTime_Monotonic`,
- but don't set an exception on error and don't require holding the GIL.
+ but don't set an exception on error and don't require an :term:`attached thread state`.
.. c:function:: int PyTime_PerfCounterRaw(PyTime_t *result)
Similar to :c:func:`PyTime_PerfCounter`,
- but don't set an exception on error and don't require holding the GIL.
+ but don't set an exception on error and don't require an :term:`attached thread state`.
.. c:function:: int PyTime_TimeRaw(PyTime_t *result)
Similar to :c:func:`PyTime_Time`,
- but don't set an exception on error and don't require holding the GIL.
+ but don't set an exception on error and don't require an :term:`attached thread state`.
Conversion functions
diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst
index 444b3456f051d8..2176b8e492f306 100644
--- a/Doc/c-api/type.rst
+++ b/Doc/c-api/type.rst
@@ -82,6 +82,9 @@ Type Objects
error (e.g. no more watcher IDs available), return ``-1`` and set an
exception.
+ In free-threaded builds, :c:func:`PyType_AddWatcher` is not thread-safe,
+ so it must be called at start up (before spawning the first thread).
+
.. versionadded:: 3.12
@@ -148,14 +151,29 @@ Type Objects
.. c:function:: PyObject* PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
- Generic handler for the :c:member:`~PyTypeObject.tp_alloc` slot of a type object. Use
- Python's default memory allocation mechanism to allocate a new instance and
- initialize all its contents to ``NULL``.
+ Generic handler for the :c:member:`~PyTypeObject.tp_alloc` slot of a type
+ object. Uses Python's default memory allocation mechanism to allocate memory
+ for a new instance, zeros the memory, then initializes the memory as if by
+ calling :c:func:`PyObject_Init` or :c:func:`PyObject_InitVar`.
+
+ Do not call this directly to allocate memory for an object; call the type's
+ :c:member:`~PyTypeObject.tp_alloc` slot instead.
+
+ For types that support garbage collection (i.e., the
+ :c:macro:`Py_TPFLAGS_HAVE_GC` flag is set), this function behaves like
+ :c:macro:`PyObject_GC_New` or :c:macro:`PyObject_GC_NewVar` (except the
+ memory is guaranteed to be zeroed before initialization), and should be
+ paired with :c:func:`PyObject_GC_Del` in :c:member:`~PyTypeObject.tp_free`.
+ Otherwise, it behaves like :c:macro:`PyObject_New` or
+ :c:macro:`PyObject_NewVar` (except the memory is guaranteed to be zeroed
+ before initialization) and should be paired with :c:func:`PyObject_Free` in
+ :c:member:`~PyTypeObject.tp_free`.
.. c:function:: PyObject* PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
- Generic handler for the :c:member:`~PyTypeObject.tp_new` slot of a type object. Create a
- new instance using the type's :c:member:`~PyTypeObject.tp_alloc` slot.
+ Generic handler for the :c:member:`~PyTypeObject.tp_new` slot of a type
+ object. Creates a new instance using the type's
+ :c:member:`~PyTypeObject.tp_alloc` slot and returns the resulting object.
.. c:function:: int PyType_Ready(PyTypeObject *type)
@@ -311,10 +329,6 @@ The following functions and structs are used to create
Metaclasses that override :c:member:`~PyTypeObject.tp_new` are not
supported, except if ``tp_new`` is ``NULL``.
- (For backwards compatibility, other ``PyType_From*`` functions allow
- such metaclasses. They ignore ``tp_new``, which may result in incomplete
- initialization. This is deprecated and in Python 3.14+ such metaclasses will
- not be supported.)
The *bases* argument can be used to specify base classes; it can either
be only one class or a tuple of classes.
@@ -456,6 +470,9 @@ The following functions and structs are used to create
class need *in addition* to the superclass.
Use :c:func:`PyObject_GetTypeData` to get a pointer to subclass-specific
memory reserved this way.
+ For negative :c:member:`!basicsize`, Python will insert padding when
+ needed to meet :c:member:`~PyTypeObject.tp_basicsize`'s alignment
+ requirements.
.. versionchanged:: 3.12
diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst
index b41e5767e59c5f..64353a8daca5f6 100644
--- a/Doc/c-api/typeobj.rst
+++ b/Doc/c-api/typeobj.rst
@@ -2,8 +2,8 @@
.. _type-structs:
-Type Objects
-============
+Type Object Structures
+======================
Perhaps one of the most important structures of the Python object system is the
structure that defines a new type: the :c:type:`PyTypeObject` structure. Type
@@ -473,7 +473,7 @@ PyTypeObject Definition
-----------------------
The structure definition for :c:type:`PyTypeObject` can be found in
-:file:`Include/object.h`. For convenience of reference, this repeats the
+:file:`Include/cpython/object.h`. For convenience of reference, this repeats the
definition found there:
.. XXX Drop this?
@@ -537,6 +537,9 @@ PyVarObject Slots
initialized to zero. For :ref:`dynamically allocated type objects
`, this field has a special internal meaning.
+ This field should be accessed using the :c:func:`Py_SIZE()` and
+ :c:func:`Py_SET_SIZE()` macros.
+
**Inheritance:**
This field is not inherited by subtypes.
@@ -587,119 +590,208 @@ and :c:data:`PyType_Type` effectively act as defaults.)
.. c:member:: Py_ssize_t PyTypeObject.tp_basicsize
- Py_ssize_t PyTypeObject.tp_itemsize
+ Py_ssize_t PyTypeObject.tp_itemsize
These fields allow calculating the size in bytes of instances of the type.
There are two kinds of types: types with fixed-length instances have a zero
- :c:member:`~PyTypeObject.tp_itemsize` field, types with variable-length instances have a non-zero
- :c:member:`~PyTypeObject.tp_itemsize` field. For a type with fixed-length instances, all
- instances have the same size, given in :c:member:`~PyTypeObject.tp_basicsize`.
+ :c:member:`!tp_itemsize` field, types with variable-length instances have a non-zero
+ :c:member:`!tp_itemsize` field. For a type with fixed-length instances, all
+ instances have the same size, given in :c:member:`!tp_basicsize`.
+ (Exceptions to this rule can be made using
+ :c:func:`PyUnstable_Object_GC_NewWithExtraData`.)
For a type with variable-length instances, the instances must have an
- :c:member:`~PyVarObject.ob_size` field, and the instance size is :c:member:`~PyTypeObject.tp_basicsize` plus N
- times :c:member:`~PyTypeObject.tp_itemsize`, where N is the "length" of the object. The value of
- N is typically stored in the instance's :c:member:`~PyVarObject.ob_size` field. There are
- exceptions: for example, ints use a negative :c:member:`~PyVarObject.ob_size` to indicate a
- negative number, and N is ``abs(ob_size)`` there. Also, the presence of an
- :c:member:`~PyVarObject.ob_size` field in the instance layout doesn't mean that the instance
- structure is variable-length (for example, the structure for the list type has
- fixed-length instances, yet those instances have a meaningful :c:member:`~PyVarObject.ob_size`
- field).
-
- The basic size includes the fields in the instance declared by the macro
- :c:macro:`PyObject_HEAD` or :c:macro:`PyObject_VAR_HEAD` (whichever is used to
- declare the instance struct) and this in turn includes the :c:member:`~PyObject._ob_prev` and
- :c:member:`~PyObject._ob_next` fields if they are present. This means that the only correct
- way to get an initializer for the :c:member:`~PyTypeObject.tp_basicsize` is to use the
- ``sizeof`` operator on the struct used to declare the instance layout.
- The basic size does not include the GC header size.
+ :c:member:`~PyVarObject.ob_size` field, and the instance size is
+ :c:member:`!tp_basicsize` plus N times :c:member:`!tp_itemsize`,
+ where N is the "length" of the object.
+
+ Functions like :c:func:`PyObject_NewVar` will take the value of N as an
+ argument, and store in the instance's :c:member:`~PyVarObject.ob_size` field.
+ Note that the :c:member:`~PyVarObject.ob_size` field may later be used for
+ other purposes. For example, :py:type:`int` instances use the bits of
+ :c:member:`~PyVarObject.ob_size` in an implementation-defined
+ way; the underlying storage and its size should be accessed using
+ :c:func:`PyLong_Export`.
+
+ .. note::
+
+ The :c:member:`~PyVarObject.ob_size` field should be accessed using
+ the :c:func:`Py_SIZE()` and :c:func:`Py_SET_SIZE()` macros.
- A note about alignment: if the variable items require a particular alignment,
- this should be taken care of by the value of :c:member:`~PyTypeObject.tp_basicsize`. Example:
- suppose a type implements an array of ``double``. :c:member:`~PyTypeObject.tp_itemsize` is
- ``sizeof(double)``. It is the programmer's responsibility that
- :c:member:`~PyTypeObject.tp_basicsize` is a multiple of ``sizeof(double)`` (assuming this is the
- alignment requirement for ``double``).
+ Also, the presence of an :c:member:`~PyVarObject.ob_size` field in the
+ instance layout doesn't mean that the instance structure is variable-length.
+ For example, the :py:type:`list` type has fixed-length instances, yet those
+ instances have a :c:member:`~PyVarObject.ob_size` field.
+ (As with :py:type:`int`, avoid reading lists' :c:member:`!ob_size` directly.
+ Call :c:func:`PyList_Size` instead.)
- For any type with variable-length instances, this field must not be ``NULL``.
+ The :c:member:`!tp_basicsize` includes size needed for data of the type's
+ :c:member:`~PyTypeObject.tp_base`, plus any extra data needed
+ by each instance.
+
+ The correct way to set :c:member:`!tp_basicsize` is to use the
+ ``sizeof`` operator on the struct used to declare the instance layout.
+ This struct must include the struct used to declare the base type.
+ In other words, :c:member:`!tp_basicsize` must be greater than or equal
+ to the base's :c:member:`!tp_basicsize`.
+
+ Since every type is a subtype of :py:type:`object`, this struct must
+ include :c:type:`PyObject` or :c:type:`PyVarObject` (depending on
+ whether :c:member:`~PyVarObject.ob_size` should be included). These are
+ usually defined by the macro :c:macro:`PyObject_HEAD` or
+ :c:macro:`PyObject_VAR_HEAD`, respectively.
+
+ The basic size does not include the GC header size, as that header is not
+ part of :c:macro:`PyObject_HEAD`.
+
+ For cases where struct used to declare the base type is unknown,
+ see :c:member:`PyType_Spec.basicsize` and :c:func:`PyType_FromMetaclass`.
+
+ Notes about alignment:
+
+ - :c:member:`!tp_basicsize` must be a multiple of ``_Alignof(PyObject)``.
+ When using ``sizeof`` on a ``struct`` that includes
+ :c:macro:`PyObject_HEAD`, as recommended, the compiler ensures this.
+ When not using a C ``struct``, or when using compiler
+ extensions like ``__attribute__((packed))``, it is up to you.
+ - If the variable items require a particular alignment,
+ :c:member:`!tp_basicsize` and :c:member:`!tp_itemsize` must each be a
+ multiple of that alignment.
+ For example, if a type's variable part stores a ``double``, it is
+ your responsibility that both fields are a multiple of
+ ``_Alignof(double)``.
**Inheritance:**
- These fields are inherited separately by subtypes. If the base type has a
- non-zero :c:member:`~PyTypeObject.tp_itemsize`, it is generally not safe to set
+ These fields are inherited separately by subtypes.
+ (That is, if the field is set to zero, :c:func:`PyType_Ready` will copy
+ the value from the base type, indicating that the instances do not
+ need additional storage.)
+
+ If the base type has a non-zero :c:member:`~PyTypeObject.tp_itemsize`, it is generally not safe to set
:c:member:`~PyTypeObject.tp_itemsize` to a different non-zero value in a subtype (though this
depends on the implementation of the base type).
.. c:member:: destructor PyTypeObject.tp_dealloc
- A pointer to the instance destructor function. This function must be defined
- unless the type guarantees that its instances will never be deallocated (as is
- the case for the singletons ``None`` and ``Ellipsis``). The function signature is::
+ A pointer to the instance destructor function. The function signature is::
void tp_dealloc(PyObject *self);
- The destructor function is called by the :c:func:`Py_DECREF` and
- :c:func:`Py_XDECREF` macros when the new reference count is zero. At this point,
- the instance is still in existence, but there are no references to it. The
- destructor function should free all references which the instance owns, free all
- memory buffers owned by the instance (using the freeing function corresponding
- to the allocation function used to allocate the buffer), and call the type's
- :c:member:`~PyTypeObject.tp_free` function. If the type is not subtypable
- (doesn't have the :c:macro:`Py_TPFLAGS_BASETYPE` flag bit set), it is
- permissible to call the object deallocator directly instead of via
- :c:member:`~PyTypeObject.tp_free`. The object deallocator should be the one used to allocate the
- instance; this is normally :c:func:`PyObject_Free` if the instance was allocated
- using :c:macro:`PyObject_New` or :c:macro:`PyObject_NewVar`, or
- :c:func:`PyObject_GC_Del` if the instance was allocated using
- :c:macro:`PyObject_GC_New` or :c:macro:`PyObject_GC_NewVar`.
-
- If the type supports garbage collection (has the :c:macro:`Py_TPFLAGS_HAVE_GC`
- flag bit set), the destructor should call :c:func:`PyObject_GC_UnTrack`
+ The destructor function should remove all references which the instance owns
+ (e.g., call :c:func:`Py_CLEAR`), free all memory buffers owned by the
+ instance, and call the type's :c:member:`~PyTypeObject.tp_free` function to
+ free the object itself.
+
+ No guarantees are made about when an object is destroyed, except:
+
+ * Python will destroy an object immediately or some time after the final
+ reference to the object is deleted, unless its finalizer
+ (:c:member:`~PyTypeObject.tp_finalize`) subsequently resurrects the
+ object.
+ * An object will not be destroyed while it is being automatically finalized
+ (:c:member:`~PyTypeObject.tp_finalize`) or automatically cleared
+ (:c:member:`~PyTypeObject.tp_clear`).
+
+ CPython currently destroys an object immediately from :c:func:`Py_DECREF`
+ when the new reference count is zero, but this may change in a future
+ version.
+
+ It is recommended to call :c:func:`PyObject_CallFinalizerFromDealloc` at the
+ beginning of :c:member:`!tp_dealloc` to guarantee that the object is always
+ finalized before destruction.
+
+ If the type supports garbage collection (the :c:macro:`Py_TPFLAGS_HAVE_GC`
+ flag is set), the destructor should call :c:func:`PyObject_GC_UnTrack`
before clearing any member fields.
- .. code-block:: c
+ It is permissible to call :c:member:`~PyTypeObject.tp_clear` from
+ :c:member:`!tp_dealloc` to reduce code duplication and to guarantee that the
+ object is always cleared before destruction. Beware that
+ :c:member:`!tp_clear` might have already been called.
- static void foo_dealloc(foo_object *self) {
+ If the type is heap allocated (:c:macro:`Py_TPFLAGS_HEAPTYPE`), the
+ deallocator should release the owned reference to its type object (via
+ :c:func:`Py_DECREF`) after calling the type deallocator. See the example
+ code below.::
+
+ static void
+ foo_dealloc(PyObject *op)
+ {
+ foo_object *self = (foo_object *) op;
PyObject_GC_UnTrack(self);
Py_CLEAR(self->ref);
- Py_TYPE(self)->tp_free((PyObject *)self);
- }
+ Py_TYPE(self)->tp_free(self);
+ }
- Finally, if the type is heap allocated (:c:macro:`Py_TPFLAGS_HEAPTYPE`), the
- deallocator should release the owned reference to its type object
- (via :c:func:`Py_DECREF`) after
- calling the type deallocator. In order to avoid dangling pointers, the
- recommended way to achieve this is:
+ :c:member:`!tp_dealloc` must leave the exception status unchanged. If it
+ needs to call something that might raise an exception, the exception state
+ must be backed up first and restored later (after logging any exceptions
+ with :c:func:`PyErr_WriteUnraisable`).
- .. code-block:: c
+ Example::
- static void foo_dealloc(foo_object *self) {
- PyTypeObject *tp = Py_TYPE(self);
- // free references and buffers here
- tp->tp_free(self);
- Py_DECREF(tp);
- }
+ static void
+ foo_dealloc(PyObject *self)
+ {
+ PyObject *exc = PyErr_GetRaisedException();
- .. warning::
+ if (PyObject_CallFinalizerFromDealloc(self) < 0) {
+ // self was resurrected.
+ goto done;
+ }
+
+ PyTypeObject *tp = Py_TYPE(self);
+
+ if (tp->tp_flags & Py_TPFLAGS_HAVE_GC) {
+ PyObject_GC_UnTrack(self);
+ }
- In a garbage collected Python, :c:member:`!tp_dealloc` may be called from
- any Python thread, not just the thread which created the object (if the
- object becomes part of a refcount cycle, that cycle might be collected by
- a garbage collection on any thread). This is not a problem for Python
- API calls, since the thread on which :c:member:`!tp_dealloc` is called
- will own the Global Interpreter Lock (GIL). However, if the object being
- destroyed in turn destroys objects from some other C or C++ library, care
- should be taken to ensure that destroying those objects on the thread
- which called :c:member:`!tp_dealloc` will not violate any assumptions of
- the library.
+ // Optional, but convenient to avoid code duplication.
+ if (tp->tp_clear && tp->tp_clear(self) < 0) {
+ PyErr_WriteUnraisable(self);
+ }
+
+ // Any additional destruction goes here.
+
+ tp->tp_free(self);
+ self = NULL; // In case PyErr_WriteUnraisable() is called below.
+
+ if (tp->tp_flags & Py_TPFLAGS_HEAPTYPE) {
+ Py_CLEAR(tp);
+ }
+
+ done:
+ // Optional, if something was called that might have raised an
+ // exception.
+ if (PyErr_Occurred()) {
+ PyErr_WriteUnraisable(self);
+ }
+ PyErr_SetRaisedException(exc);
+ }
+
+ :c:member:`!tp_dealloc` may be called from
+ any Python thread, not just the thread which created the object (if the
+ object becomes part of a refcount cycle, that cycle might be collected by
+ a garbage collection on any thread). This is not a problem for Python
+ API calls, since the thread on which :c:member:`!tp_dealloc` is called
+ with an :term:`attached thread state`. However, if the object being
+ destroyed in turn destroys objects from some other C library, care
+ should be taken to ensure that destroying those objects on the thread
+ which called :c:member:`!tp_dealloc` will not violate any assumptions of
+ the library.
**Inheritance:**
This field is inherited by subtypes.
+ .. seealso::
+
+ :ref:`life-cycle` for details about how this slot relates to other slots.
+
.. c:member:: Py_ssize_t PyTypeObject.tp_vectorcall_offset
@@ -1090,11 +1182,11 @@ and :c:data:`PyType_Type` effectively act as defaults.)
.. c:macro:: Py_TPFLAGS_HAVE_GC
This bit is set when the object supports garbage collection. If this bit
- is set, instances must be created using :c:macro:`PyObject_GC_New` and
- destroyed using :c:func:`PyObject_GC_Del`. More information in section
- :ref:`supporting-cycle-detection`. This bit also implies that the
- GC-related fields :c:member:`~PyTypeObject.tp_traverse` and :c:member:`~PyTypeObject.tp_clear` are present in
- the type object.
+ is set, memory for new instances (see :c:member:`~PyTypeObject.tp_alloc`)
+ must be allocated using :c:macro:`PyObject_GC_New` or
+ :c:func:`PyType_GenericAlloc` and deallocated (see
+ :c:member:`~PyTypeObject.tp_free`) using :c:func:`PyObject_GC_Del`. More
+ information in section :ref:`supporting-cycle-detection`.
**Inheritance:**
@@ -1374,8 +1466,9 @@ and :c:data:`PyType_Type` effectively act as defaults.)
:mod:`!_thread` extension module::
static int
- local_traverse(localobject *self, visitproc visit, void *arg)
+ local_traverse(PyObject *op, visitproc visit, void *arg)
{
+ localobject *self = (localobject *) op;
Py_VISIT(self->args);
Py_VISIT(self->kw);
Py_VISIT(self->dict);
@@ -1430,6 +1523,11 @@ and :c:data:`PyType_Type` effectively act as defaults.)
heap-allocated superclass).
If they do not, the type object may not be garbage-collected.
+ .. note::
+
+ The :c:member:`~PyTypeObject.tp_traverse` function can be called from any
+ thread.
+
.. versionchanged:: 3.9
Heap-allocated types are expected to visit ``Py_TYPE(self)`` in
@@ -1449,28 +1547,110 @@ and :c:data:`PyType_Type` effectively act as defaults.)
.. c:member:: inquiry PyTypeObject.tp_clear
- An optional pointer to a clear function for the garbage collector. This is only
- used if the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit is set. The signature is::
+ An optional pointer to a clear function. The signature is::
int tp_clear(PyObject *);
- The :c:member:`~PyTypeObject.tp_clear` member function is used to break reference cycles in cyclic
- garbage detected by the garbage collector. Taken together, all :c:member:`~PyTypeObject.tp_clear`
- functions in the system must combine to break all reference cycles. This is
- subtle, and if in any doubt supply a :c:member:`~PyTypeObject.tp_clear` function. For example,
- the tuple type does not implement a :c:member:`~PyTypeObject.tp_clear` function, because it's
- possible to prove that no reference cycle can be composed entirely of tuples.
- Therefore the :c:member:`~PyTypeObject.tp_clear` functions of other types must be sufficient to
- break any cycle containing a tuple. This isn't immediately obvious, and there's
- rarely a good reason to avoid implementing :c:member:`~PyTypeObject.tp_clear`.
+ The purpose of this function is to break reference cycles that are causing a
+ :term:`cyclic isolate` so that the objects can be safely destroyed. A
+ cleared object is a partially destroyed object; the object is not obligated
+ to satisfy design invariants held during normal use.
+
+ :c:member:`!tp_clear` does not need to delete references to objects that
+ can't participate in reference cycles, such as Python strings or Python
+ integers. However, it may be convenient to clear all references, and write
+ the type's :c:member:`~PyTypeObject.tp_dealloc` function to invoke
+ :c:member:`!tp_clear` to avoid code duplication. (Beware that
+ :c:member:`!tp_clear` might have already been called. Prefer calling
+ idempotent functions like :c:func:`Py_CLEAR`.)
+
+ Any non-trivial cleanup should be performed in
+ :c:member:`~PyTypeObject.tp_finalize` instead of :c:member:`!tp_clear`.
+
+ .. note::
+
+ If :c:member:`!tp_clear` fails to break a reference cycle then the
+ objects in the :term:`cyclic isolate` may remain indefinitely
+ uncollectable ("leak"). See :data:`gc.garbage`.
+
+ .. note::
+
+ Referents (direct and indirect) might have already been cleared; they are
+ not guaranteed to be in a consistent state.
+
+ .. note::
+
+ The :c:member:`~PyTypeObject.tp_clear` function can be called from any
+ thread.
+
+ .. note::
+
+ An object is not guaranteed to be automatically cleared before its
+ destructor (:c:member:`~PyTypeObject.tp_dealloc`) is called.
+
+ This function differs from the destructor
+ (:c:member:`~PyTypeObject.tp_dealloc`) in the following ways:
+
+ * The purpose of clearing an object is to remove references to other objects
+ that might participate in a reference cycle. The purpose of the
+ destructor, on the other hand, is a superset: it must release *all*
+ resources it owns, including references to objects that cannot participate
+ in a reference cycle (e.g., integers) as well as the object's own memory
+ (by calling :c:member:`~PyTypeObject.tp_free`).
+ * When :c:member:`!tp_clear` is called, other objects might still hold
+ references to the object being cleared. Because of this,
+ :c:member:`!tp_clear` must not deallocate the object's own memory
+ (:c:member:`~PyTypeObject.tp_free`). The destructor, on the other hand,
+ is only called when no (strong) references exist, and as such, must
+ safely destroy the object itself by deallocating it.
+ * :c:member:`!tp_clear` might never be automatically called. An object's
+ destructor, on the other hand, will be automatically called some time
+ after the object becomes unreachable (i.e., either there are no references
+ to the object or the object is a member of a :term:`cyclic isolate`).
+
+ No guarantees are made about when, if, or how often Python automatically
+ clears an object, except:
+
+ * Python will not automatically clear an object if it is reachable, i.e.,
+ there is a reference to it and it is not a member of a :term:`cyclic
+ isolate`.
+ * Python will not automatically clear an object if it has not been
+ automatically finalized (see :c:member:`~PyTypeObject.tp_finalize`). (If
+ the finalizer resurrected the object, the object may or may not be
+ automatically finalized again before it is cleared.)
+ * If an object is a member of a :term:`cyclic isolate`, Python will not
+ automatically clear it if any member of the cyclic isolate has not yet
+ been automatically finalized (:c:member:`~PyTypeObject.tp_finalize`).
+ * Python will not destroy an object until after any automatic calls to its
+ :c:member:`!tp_clear` function have returned. This ensures that the act
+ of breaking a reference cycle does not invalidate the ``self`` pointer
+ while :c:member:`!tp_clear` is still executing.
+ * Python will not automatically call :c:member:`!tp_clear` multiple times
+ concurrently.
+
+ CPython currently only automatically clears objects as needed to break
+ reference cycles in a :term:`cyclic isolate`, but future versions might
+ clear objects regularly before their destruction.
+
+ Taken together, all :c:member:`~PyTypeObject.tp_clear` functions in the
+ system must combine to break all reference cycles. This is subtle, and if
+ in any doubt supply a :c:member:`~PyTypeObject.tp_clear` function. For
+ example, the tuple type does not implement a
+ :c:member:`~PyTypeObject.tp_clear` function, because it's possible to prove
+ that no reference cycle can be composed entirely of tuples. Therefore the
+ :c:member:`~PyTypeObject.tp_clear` functions of other types are responsible
+ for breaking any cycle containing a tuple. This isn't immediately obvious,
+ and there's rarely a good reason to avoid implementing
+ :c:member:`~PyTypeObject.tp_clear`.
Implementations of :c:member:`~PyTypeObject.tp_clear` should drop the instance's references to
those of its members that may be Python objects, and set its pointers to those
members to ``NULL``, as in the following example::
static int
- local_clear(localobject *self)
+ local_clear(PyObject *op)
{
+ localobject *self = (localobject *) op;
Py_CLEAR(self->key);
Py_CLEAR(self->args);
Py_CLEAR(self->kw);
@@ -1496,18 +1676,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
PyObject_ClearManagedDict((PyObject*)self);
- Note that :c:member:`~PyTypeObject.tp_clear` is not *always* called
- before an instance is deallocated. For example, when reference counting
- is enough to determine that an object is no longer used, the cyclic garbage
- collector is not involved and :c:member:`~PyTypeObject.tp_dealloc` is
- called directly.
-
- Because the goal of :c:member:`~PyTypeObject.tp_clear` functions is to break reference cycles,
- it's not necessary to clear contained objects like Python strings or Python
- integers, which can't participate in reference cycles. On the other hand, it may
- be convenient to clear all contained Python objects, and write the type's
- :c:member:`~PyTypeObject.tp_dealloc` function to invoke :c:member:`~PyTypeObject.tp_clear`.
-
More information about Python's garbage collection scheme can be found in
section :ref:`supporting-cycle-detection`.
@@ -1520,6 +1688,10 @@ and :c:data:`PyType_Type` effectively act as defaults.)
:c:member:`~PyTypeObject.tp_clear` are all inherited from the base type if they are all zero in
the subtype.
+ .. seealso::
+
+ :ref:`life-cycle` for details about how this slot relates to other slots.
+
.. c:member:: richcmpfunc PyTypeObject.tp_richcompare
@@ -1896,18 +2068,17 @@ and :c:data:`PyType_Type` effectively act as defaults.)
**Inheritance:**
- This field is inherited by static subtypes, but not by dynamic
- subtypes (subtypes created by a class statement).
+ Static subtypes inherit this slot, which will be
+ :c:func:`PyType_GenericAlloc` if inherited from :class:`object`.
+
+ :ref:`Heap subtypes ` do not inherit this slot.
**Default:**
- For dynamic subtypes, this field is always set to
- :c:func:`PyType_GenericAlloc`, to force a standard heap
- allocation strategy.
+ For heap subtypes, this field is always set to
+ :c:func:`PyType_GenericAlloc`.
- For static subtypes, :c:data:`PyBaseObject_Type` uses
- :c:func:`PyType_GenericAlloc`. That is the recommended value
- for all statically defined types.
+ For static subtypes, this slot is inherited (see above).
.. c:member:: newfunc PyTypeObject.tp_new
@@ -1955,20 +2126,27 @@ and :c:data:`PyType_Type` effectively act as defaults.)
void tp_free(void *self);
- An initializer that is compatible with this signature is :c:func:`PyObject_Free`.
+ This function must free the memory allocated by
+ :c:member:`~PyTypeObject.tp_alloc`.
**Inheritance:**
- This field is inherited by static subtypes, but not by dynamic
- subtypes (subtypes created by a class statement)
+ Static subtypes inherit this slot, which will be :c:func:`PyObject_Free` if
+ inherited from :class:`object`. Exception: If the type supports garbage
+ collection (i.e., the :c:macro:`Py_TPFLAGS_HAVE_GC` flag is set in
+ :c:member:`~PyTypeObject.tp_flags`) and it would inherit
+ :c:func:`PyObject_Free`, then this slot is not inherited but instead defaults
+ to :c:func:`PyObject_GC_Del`.
+
+ :ref:`Heap subtypes ` do not inherit this slot.
**Default:**
- In dynamic subtypes, this field is set to a deallocator suitable to
- match :c:func:`PyType_GenericAlloc` and the value of the
- :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit.
+ For :ref:`heap subtypes `, this slot defaults to a deallocator suitable to match
+ :c:func:`PyType_GenericAlloc` and the value of the
+ :c:macro:`Py_TPFLAGS_HAVE_GC` flag.
- For static subtypes, :c:data:`PyBaseObject_Type` uses :c:func:`PyObject_Free`.
+ For static subtypes, this slot is inherited (see above).
.. c:member:: inquiry PyTypeObject.tp_is_gc
@@ -2095,32 +2273,139 @@ and :c:data:`PyType_Type` effectively act as defaults.)
.. c:member:: destructor PyTypeObject.tp_finalize
- An optional pointer to an instance finalization function. Its signature is::
+ An optional pointer to an instance finalization function. This is the C
+ implementation of the :meth:`~object.__del__` special method. Its signature
+ is::
void tp_finalize(PyObject *self);
- If :c:member:`~PyTypeObject.tp_finalize` is set, the interpreter calls it once when
- finalizing an instance. It is called either from the garbage
- collector (if the instance is part of an isolated reference cycle) or
- just before the object is deallocated. Either way, it is guaranteed
- to be called before attempting to break reference cycles, ensuring
- that it finds the object in a sane state.
+ The primary purpose of finalization is to perform any non-trivial cleanup
+ that must be performed before the object is destroyed, while the object and
+ any other objects it directly or indirectly references are still in a
+ consistent state. The finalizer is allowed to execute
+ arbitrary Python code.
+
+ Before Python automatically finalizes an object, some of the object's direct
+ or indirect referents might have themselves been automatically finalized.
+ However, none of the referents will have been automatically cleared
+ (:c:member:`~PyTypeObject.tp_clear`) yet.
+
+ Other non-finalized objects might still be using a finalized object, so the
+ finalizer must leave the object in a sane state (e.g., invariants are still
+ met).
- :c:member:`~PyTypeObject.tp_finalize` should not mutate the current exception status;
- therefore, a recommended way to write a non-trivial finalizer is::
+ .. note::
+
+ After Python automatically finalizes an object, Python might start
+ automatically clearing (:c:member:`~PyTypeObject.tp_clear`) the object
+ and its referents (direct and indirect). Cleared objects are not
+ guaranteed to be in a consistent state; a finalized object must be able
+ to tolerate cleared referents.
+
+ .. note::
+
+ An object is not guaranteed to be automatically finalized before its
+ destructor (:c:member:`~PyTypeObject.tp_dealloc`) is called. It is
+ recommended to call :c:func:`PyObject_CallFinalizerFromDealloc` at the
+ beginning of :c:member:`!tp_dealloc` to guarantee that the object is
+ always finalized before destruction.
+
+ .. note::
+
+ The :c:member:`~PyTypeObject.tp_finalize` function can be called from any
+ thread, although the :term:`GIL` will be held.
+
+ .. note::
+
+ The :c:member:`!tp_finalize` function can be called during shutdown,
+ after some global variables have been deleted. See the documentation of
+ the :meth:`~object.__del__` method for details.
+
+ When Python finalizes an object, it behaves like the following algorithm:
+
+ #. Python might mark the object as *finalized*. Currently, Python always
+ marks objects whose type supports garbage collection (i.e., the
+ :c:macro:`Py_TPFLAGS_HAVE_GC` flag is set in
+ :c:member:`~PyTypeObject.tp_flags`) and never marks other types of
+ objects; this might change in a future version.
+ #. If the object is not marked as *finalized* and its
+ :c:member:`!tp_finalize` finalizer function is non-``NULL``, the
+ finalizer function is called.
+ #. If the finalizer function was called and the finalizer made the object
+ reachable (i.e., there is a reference to the object and it is not a
+ member of a :term:`cyclic isolate`), then the finalizer is said to have
+ *resurrected* the object. It is unspecified whether the finalizer can
+ also resurrect the object by adding a new reference to the object that
+ does not make it reachable, i.e., the object is (still) a member of a
+ cyclic isolate.
+ #. If the finalizer resurrected the object, the object's pending destruction
+ is canceled and the object's *finalized* mark might be removed if
+ present. Currently, Python never removes the *finalized* mark; this
+ might change in a future version.
+
+ *Automatic finalization* refers to any finalization performed by Python
+ except via calls to :c:func:`PyObject_CallFinalizer` or
+ :c:func:`PyObject_CallFinalizerFromDealloc`. No guarantees are made about
+ when, if, or how often an object is automatically finalized, except:
+
+ * Python will not automatically finalize an object if it is reachable, i.e.,
+ there is a reference to it and it is not a member of a :term:`cyclic
+ isolate`.
+ * Python will not automatically finalize an object if finalizing it would
+ not mark the object as *finalized*. Currently, this applies to objects
+ whose type does not support garbage collection, i.e., the
+ :c:macro:`Py_TPFLAGS_HAVE_GC` flag is not set. Such objects can still be
+ manually finalized by calling :c:func:`PyObject_CallFinalizer` or
+ :c:func:`PyObject_CallFinalizerFromDealloc`.
+ * Python will not automatically finalize any two members of a :term:`cyclic
+ isolate` concurrently.
+ * Python will not automatically finalize an object after it has
+ automatically cleared (:c:member:`~PyTypeObject.tp_clear`) the object.
+ * If an object is a member of a :term:`cyclic isolate`, Python will not
+ automatically finalize it after automatically clearing (see
+ :c:member:`~PyTypeObject.tp_clear`) any other member.
+ * Python will automatically finalize every member of a :term:`cyclic
+ isolate` before it automatically clears (see
+ :c:member:`~PyTypeObject.tp_clear`) any of them.
+ * If Python is going to automatically clear an object
+ (:c:member:`~PyTypeObject.tp_clear`), it will automatically finalize the
+ object first.
+
+ Python currently only automatically finalizes objects that are members of a
+ :term:`cyclic isolate`, but future versions might finalize objects regularly
+ before their destruction.
+
+ To manually finalize an object, do not call this function directly; call
+ :c:func:`PyObject_CallFinalizer` or
+ :c:func:`PyObject_CallFinalizerFromDealloc` instead.
+
+ :c:member:`~PyTypeObject.tp_finalize` should leave the current exception
+ status unchanged. The recommended way to write a non-trivial finalizer is
+ to back up the exception at the beginning by calling
+ :c:func:`PyErr_GetRaisedException` and restore the exception at the end by
+ calling :c:func:`PyErr_SetRaisedException`. If an exception is encountered
+ in the middle of the finalizer, log and clear it with
+ :c:func:`PyErr_WriteUnraisable` or :c:func:`PyErr_FormatUnraisable`. For
+ example::
static void
- local_finalize(PyObject *self)
+ foo_finalize(PyObject *self)
{
- PyObject *error_type, *error_value, *error_traceback;
+ // Save the current exception, if any.
+ PyObject *exc = PyErr_GetRaisedException();
- /* Save the current exception, if any. */
- PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ // ...
- /* ... */
+ if (do_something_that_might_raise() != success_indicator) {
+ PyErr_WriteUnraisable(self);
+ goto done;
+ }
- /* Restore the saved exception. */
- PyErr_Restore(error_type, error_value, error_traceback);
+ done:
+ // Restore the saved exception. This silently discards any exception
+ // raised above, so be sure to call PyErr_WriteUnraisable first if
+ // necessary.
+ PyErr_SetRaisedException(exc);
}
**Inheritance:**
@@ -2135,7 +2420,13 @@ and :c:data:`PyType_Type` effectively act as defaults.)
:c:macro:`Py_TPFLAGS_HAVE_FINALIZE` flags bit in order for this field to be
used. This is no longer required.
- .. seealso:: "Safe object finalization" (:pep:`442`)
+ .. seealso::
+
+ * :pep:`442`: "Safe object finalization"
+ * :ref:`life-cycle` for details about how this slot relates to other
+ slots.
+ * :c:func:`PyObject_CallFinalizer`
+ * :c:func:`PyObject_CallFinalizerFromDealloc`
.. c:member:: vectorcallfunc PyTypeObject.tp_vectorcall
diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst
index e79aa94036e207..cdd90d05b70b36 100644
--- a/Doc/c-api/unicode.rst
+++ b/Doc/c-api/unicode.rst
@@ -31,6 +31,18 @@ Unicode Type
These are the basic Unicode object types used for the Unicode implementation in
Python:
+.. c:var:: PyTypeObject PyUnicode_Type
+
+ This instance of :c:type:`PyTypeObject` represents the Python Unicode type.
+ It is exposed to Python code as :py:class:`str`.
+
+
+.. c:var:: PyTypeObject PyUnicodeIter_Type
+
+ This instance of :c:type:`PyTypeObject` represents the Python Unicode
+ iterator type. It is used to iterate over Unicode string objects.
+
+
.. c:type:: Py_UCS4
Py_UCS2
Py_UCS1
@@ -42,19 +54,6 @@ Python:
.. versionadded:: 3.3
-.. c:type:: Py_UNICODE
-
- This is a typedef of :c:type:`wchar_t`, which is a 16-bit type or 32-bit type
- depending on the platform.
-
- .. versionchanged:: 3.3
- In previous versions, this was a 16-bit type or a 32-bit type depending on
- whether you selected a "narrow" or "wide" Unicode version of Python at
- build time.
-
- .. deprecated-removed:: 3.13 3.15
-
-
.. c:type:: PyASCIIObject
PyCompactUnicodeObject
PyUnicodeObject
@@ -66,12 +65,6 @@ Python:
.. versionadded:: 3.3
-.. c:var:: PyTypeObject PyUnicode_Type
-
- This instance of :c:type:`PyTypeObject` represents the Python Unicode type. It
- is exposed to Python code as ``str``.
-
-
The following APIs are C macros and static inlined functions for fast checks and
access to internal read-only data of Unicode objects:
@@ -87,16 +80,6 @@ access to internal read-only data of Unicode objects:
subtype. This function always succeeds.
-.. c:function:: int PyUnicode_READY(PyObject *unicode)
-
- Returns ``0``. This API is kept only for backward compatibility.
-
- .. versionadded:: 3.3
-
- .. deprecated:: 3.10
- This API does nothing since Python 3.12.
-
-
.. c:function:: Py_ssize_t PyUnicode_GET_LENGTH(PyObject *unicode)
Return the length of the Unicode string, in code points. *unicode* has to be a
@@ -149,12 +132,16 @@ access to internal read-only data of Unicode objects:
.. c:function:: void PyUnicode_WRITE(int kind, void *data, \
Py_ssize_t index, Py_UCS4 value)
- Write into a canonical representation *data* (as obtained with
- :c:func:`PyUnicode_DATA`). This function performs no sanity checks, and is
- intended for usage in loops. The caller should cache the *kind* value and
- *data* pointer as obtained from other calls. *index* is the index in
- the string (starts at 0) and *value* is the new code point value which should
- be written to that location.
+ Write the code point *value* to the given zero-based *index* in a string.
+
+ The *kind* value and *data* pointer must have been obtained from a
+ string using :c:func:`PyUnicode_KIND` and :c:func:`PyUnicode_DATA`
+ respectively. You must hold a reference to that string while calling
+ :c:func:`!PyUnicode_WRITE`. All requirements of
+ :c:func:`PyUnicode_WriteChar` also apply.
+
+ The function performs no checks for any of its requirements,
+ and is intended for usage in loops.
.. versionadded:: 3.3
@@ -196,6 +183,14 @@ access to internal read-only data of Unicode objects:
is not ready.
+.. c:function:: unsigned int PyUnicode_IS_ASCII(PyObject *unicode)
+
+ Return true if the string only contains ASCII characters.
+ Equivalent to :py:meth:`str.isascii`.
+
+ .. versionadded:: 3.2
+
+
Unicode Character Properties
""""""""""""""""""""""""""""
@@ -330,11 +325,29 @@ APIs:
to be placed in the string. As an approximation, it can be rounded up to the
nearest value in the sequence 127, 255, 65535, 1114111.
- This is the recommended way to allocate a new Unicode object. Objects
- created using this function are not resizable.
-
On error, set an exception and return ``NULL``.
+ After creation, the string can be filled by :c:func:`PyUnicode_WriteChar`,
+ :c:func:`PyUnicode_CopyCharacters`, :c:func:`PyUnicode_Fill`,
+ :c:func:`PyUnicode_WRITE` or similar.
+ Since strings are supposed to be immutable, take care to not “use” the
+ result while it is being modified. In particular, before it's filled
+ with its final contents, a string:
+
+ - must not be hashed,
+ - must not be :c:func:`converted to UTF-8 `,
+ or another non-"canonical" representation,
+ - must not have its reference count changed,
+ - must not be shared with code that might do one of the above.
+
+ This list is not exhaustive. Avoiding these uses is your responsibility;
+ Python does not always check these requirements.
+
+ To avoid accidentally exposing a partially-written string object, prefer
+ using the :c:type:`PyUnicodeWriter` API, or one of the ``PyUnicode_From*``
+ functions below.
+
+
.. versionadded:: 3.3
@@ -589,6 +602,14 @@ APIs:
Objects other than Unicode or its subtypes will cause a :exc:`TypeError`.
+.. c:function:: PyObject* PyUnicode_FromOrdinal(int ordinal)
+
+ Create a Unicode Object from the given Unicode code point *ordinal*.
+
+ The ordinal must be in ``range(0x110000)``. A :exc:`ValueError` is
+ raised in the case it is not.
+
+
.. c:function:: PyObject* PyUnicode_FromEncodedObject(PyObject *obj, \
const char *encoding, const char *errors)
@@ -607,6 +628,43 @@ APIs:
decref'ing the returned objects.
+.. c:function:: void PyUnicode_Append(PyObject **p_left, PyObject *right)
+
+ Append the string *right* to the end of *p_left*.
+ *p_left* must point to a :term:`strong reference` to a Unicode object;
+ :c:func:`!PyUnicode_Append` releases ("steals") this reference.
+
+ On error, set *\*p_left* to ``NULL`` and set an exception.
+
+ On success, set *\*p_left* to a new strong reference to the result.
+
+
+.. c:function:: void PyUnicode_AppendAndDel(PyObject **p_left, PyObject *right)
+
+ The function is similar to :c:func:`PyUnicode_Append`, with the only
+ difference being that it decrements the reference count of *right* by one.
+
+
+.. c:function:: PyObject* PyUnicode_BuildEncodingMap(PyObject* string)
+
+ Return a mapping suitable for decoding a custom single-byte encoding.
+ Given a Unicode string *string* of up to 256 characters representing an encoding
+ table, returns either a compact internal mapping object or a dictionary
+ mapping character ordinals to byte values. Raises a :exc:`TypeError` and
+ return ``NULL`` on invalid input.
+
+ .. versionadded:: 3.2
+
+
+.. c:function:: const char* PyUnicode_GetDefaultEncoding(void)
+
+ Return the name of the default string encoding, ``"utf-8"``.
+ See :func:`sys.getdefaultencoding`.
+
+ The returned string does not need to be freed, and is valid
+ until interpreter shutdown.
+
+
.. c:function:: Py_ssize_t PyUnicode_GetLength(PyObject *unicode)
Return the length of the Unicode object, in code points.
@@ -627,9 +685,27 @@ APIs:
possible. Returns ``-1`` and sets an exception on error, otherwise returns
the number of copied characters.
+ The string must not have been “used” yet.
+ See :c:func:`PyUnicode_New` for details.
+
.. versionadded:: 3.3
+.. c:function:: int PyUnicode_Resize(PyObject **unicode, Py_ssize_t length);
+
+ Resize a Unicode object *\*unicode* to the new *length* in code points.
+
+ Try to resize the string in place (which is usually faster than allocating
+ a new string and copying characters), or create a new string.
+
+ *\*unicode* is modified to point to the new (resized) object and ``0`` is
+ returned on success. Otherwise, ``-1`` is returned and an exception is set,
+ and *\*unicode* is left untouched.
+
+ The function doesn't check string content, the result may not be a
+ string in canonical representation.
+
+
.. c:function:: Py_ssize_t PyUnicode_Fill(PyObject *unicode, Py_ssize_t start, \
Py_ssize_t length, Py_UCS4 fill_char)
@@ -639,6 +715,9 @@ APIs:
Fail if *fill_char* is bigger than the string maximum character, or if the
string has more than 1 reference.
+ The string must not have been “used” yet.
+ See :c:func:`PyUnicode_New` for details.
+
Return the number of written character, or return ``-1`` and raise an
exception on error.
@@ -648,15 +727,16 @@ APIs:
.. c:function:: int PyUnicode_WriteChar(PyObject *unicode, Py_ssize_t index, \
Py_UCS4 character)
- Write a character to a string. The string must have been created through
- :c:func:`PyUnicode_New`. Since Unicode strings are supposed to be immutable,
- the string must not be shared, or have been hashed yet.
+ Write a *character* to the string *unicode* at the zero-based *index*.
+ Return ``0`` on success, ``-1`` on error with an exception set.
This function checks that *unicode* is a Unicode object, that the index is
- not out of bounds, and that the object can be modified safely (i.e. that it
- its reference count is one).
+ not out of bounds, and that the object's reference count is one).
+ See :c:func:`PyUnicode_WRITE` for a version that skips these checks,
+ making them your responsibility.
- Return ``0`` on success, ``-1`` on error with an exception set.
+ The string must not have been “used” yet.
+ See :c:func:`PyUnicode_New` for details.
.. versionadded:: 3.3
@@ -963,6 +1043,17 @@ generic ones are documented for simplicity.
Generic Codecs
""""""""""""""
+The following macro is provided:
+
+
+.. c:macro:: Py_UNICODE_REPLACEMENT_CHARACTER
+
+ The Unicode code point ``U+FFFD`` (replacement character).
+
+ This Unicode character is used as the replacement character during
+ decoding if the *errors* argument is set to "replace".
+
+
These are the generic codec APIs:
@@ -1640,6 +1731,20 @@ They all return ``NULL`` or ``-1`` if an exception occurs.
Strings interned this way are made :term:`immortal`.
+.. c:function:: unsigned int PyUnicode_CHECK_INTERNED(PyObject *str)
+
+ Return a non-zero value if *str* is interned, zero if not.
+ The *str* argument must be a string; this is not checked.
+ This function always succeeds.
+
+ .. impl-detail::
+
+ A non-zero return value may carry additional information
+ about *how* the string is interned.
+ The meaning of such non-zero values, as well as each specific string's
+ intern-related details, may change between CPython versions.
+
+
PyUnicodeWriter
^^^^^^^^^^^^^^^
@@ -1760,8 +1865,8 @@ object.
*size* is the string length in bytes. If *size* is equal to ``-1``, call
``strlen(str)`` to get the string length.
- *errors* is an error handler name, such as ``"replace"``. If *errors* is
- ``NULL``, use the strict error handler.
+ *errors* is an :ref:`error handler ` name, such as
+ ``"replace"``. If *errors* is ``NULL``, use the strict error handler.
If *consumed* is not ``NULL``, set *\*consumed* to the number of decoded
bytes on success.
@@ -1772,3 +1877,49 @@ object.
On error, set an exception, leave the writer unchanged, and return ``-1``.
See also :c:func:`PyUnicodeWriter_WriteUTF8`.
+
+Deprecated API
+^^^^^^^^^^^^^^
+
+The following API is deprecated.
+
+.. c:type:: Py_UNICODE
+
+ This is a typedef of :c:type:`wchar_t`, which is a 16-bit type or 32-bit type
+ depending on the platform.
+ Please use :c:type:`wchar_t` directly instead.
+
+ .. versionchanged:: 3.3
+ In previous versions, this was a 16-bit type or a 32-bit type depending on
+ whether you selected a "narrow" or "wide" Unicode version of Python at
+ build time.
+
+ .. deprecated-removed:: 3.13 3.15
+
+
+.. c:function:: int PyUnicode_READY(PyObject *unicode)
+
+ Do nothing and return ``0``.
+ This API is kept only for backward compatibility, but there are no plans
+ to remove it.
+
+ .. versionadded:: 3.3
+
+ .. deprecated:: 3.10
+ This API does nothing since Python 3.12.
+ Previously, this needed to be called for each string created using
+ the old API (:c:func:`!PyUnicode_FromUnicode` or similar).
+
+
+.. c:function:: unsigned int PyUnicode_IS_READY(PyObject *unicode)
+
+ Do nothing and return ``1``.
+ This API is kept only for backward compatibility, but there are no plans
+ to remove it.
+
+ .. versionadded:: 3.3
+
+ .. deprecated:: 3.14
+ This API does nothing since Python 3.12.
+ Previously, this could be called to check if
+ :c:func:`PyUnicode_READY` is necessary.
diff --git a/Doc/conf.py b/Doc/conf.py
index 56594f32c6d02d..7fadad66cb3238 100644
--- a/Doc/conf.py
+++ b/Doc/conf.py
@@ -6,9 +6,10 @@
# The contents of this file are pickled, so don't put values in the namespace
# that aren't pickleable (module imports are okay, they're removed automatically).
-import importlib
import os
import sys
+from importlib import import_module
+from importlib.util import find_spec
# Make our custom extensions available to Sphinx
sys.path.append(os.path.abspath('tools/extensions'))
@@ -29,6 +30,7 @@
'glossary_search',
'grammar_snippet',
'implementation_detail',
+ 'issue_role',
'lexers',
'misc_news',
'pydoc_topics',
@@ -39,19 +41,17 @@
]
# Skip if downstream redistributors haven't installed them
-try:
- import notfound.extension # noqa: F401
-except ImportError:
- pass
-else:
- extensions.append('notfound.extension')
-try:
- import sphinxext.opengraph # noqa: F401
-except ImportError:
- pass
-else:
- extensions.append('sphinxext.opengraph')
-
+_OPTIONAL_EXTENSIONS = (
+ 'notfound.extension',
+ 'sphinxext.opengraph',
+)
+for optional_ext in _OPTIONAL_EXTENSIONS:
+ try:
+ if find_spec(optional_ext) is not None:
+ extensions.append(optional_ext)
+ except (ImportError, ValueError):
+ pass
+del _OPTIONAL_EXTENSIONS
doctest_global_setup = '''
try:
@@ -74,7 +74,7 @@
# We look for the Include/patchlevel.h file in the current Python source tree
# and replace the values accordingly.
# See Doc/tools/extensions/patchlevel.py
-version, release = importlib.import_module('patchlevel').get_version_info()
+version, release = import_module('patchlevel').get_version_info()
rst_epilog = f"""
.. |python_version_literal| replace:: ``Python {version}``
@@ -100,7 +100,7 @@
# Minimum version of sphinx required
# Keep this version in sync with ``Doc/requirements.txt``.
-needs_sphinx = '8.1.3'
+needs_sphinx = '8.2.0'
# Create table of contents entries for domain objects (e.g. functions, classes,
# attributes, etc.). Default is True.
@@ -308,7 +308,6 @@
('py:attr', '__annotations__'),
('py:meth', '__missing__'),
('py:attr', '__wrapped__'),
- ('py:attr', 'decimal.Context.clamp'),
('py:meth', 'index'), # list.index, tuple.index, etc.
]
@@ -624,11 +623,19 @@
# Options for sphinxext-opengraph
# -------------------------------
-ogp_site_url = 'https://docs.python.org/3/'
+ogp_canonical_url = 'https://docs.python.org/3/'
ogp_site_name = 'Python documentation'
-ogp_image = '_static/og-image.png'
+ogp_social_cards = { # Used when matplotlib is installed
+ 'image': '_static/og-image.png',
+ 'line_color': '#3776ab',
+}
ogp_custom_meta_tags = [
- '',
- '',
- '',
+ '',
]
+if 'create-social-cards' not in tags: # noqa: F821
+ # Define a static preview image when not creating social cards
+ ogp_image = '_static/og-image.png'
+ ogp_custom_meta_tags += [
+ '',
+ '',
+ ]
diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat
index 7f576d21ff489d..59b31ccf7bc471 100644
--- a/Doc/data/refcounts.dat
+++ b/Doc/data/refcounts.dat
@@ -1093,9 +1093,6 @@ PyImport_ImportModuleLevelObject:PyObject*:locals:0:???
PyImport_ImportModuleLevelObject:PyObject*:fromlist:0:???
PyImport_ImportModuleLevelObject:int:level::
-PyImport_ImportModuleNoBlock:PyObject*::+1:
-PyImport_ImportModuleNoBlock:const char*:name::
-
PyImport_ReloadModule:PyObject*::+1:
PyImport_ReloadModule:PyObject*:m:0:
@@ -2770,6 +2767,23 @@ PyUnicode_FromFormatV:PyObject*::+1:
PyUnicode_FromFormatV:const char*:format::
PyUnicode_FromFormatV:va_list:args::
+PyUnicode_FromOrdinal:PyObject*::+1:
+PyUnicode_FromOrdinal:int:ordinal::
+
+PyUnicode_Append:void:::
+PyUnicode_Append:PyObject**:p_left:0:
+PyUnicode_Append:PyObject*:right::
+
+PyUnicode_AppendAndDel:void:::
+PyUnicode_AppendAndDel:PyObject**:p_left:0:
+PyUnicode_AppendAndDel:PyObject*:right:-1:
+
+PyUnicode_BuildEncodingMap:PyObject*::+1:
+PyUnicode_BuildEncodingMap:PyObject*:string:::
+
+PyUnicode_GetDefaultEncoding:const char*:::
+PyUnicode_GetDefaultEncoding::void::
+
PyUnicode_GetLength:Py_ssize_t:::
PyUnicode_GetLength:PyObject*:unicode:0:
@@ -2780,6 +2794,10 @@ PyUnicode_CopyCharacters:PyObject*:from:0:
PyUnicode_CopyCharacters:Py_ssize_t:from_start::
PyUnicode_CopyCharacters:Py_ssize_t:how_many::
+PyUnicode_Resize:int:::
+PyUnicode_Resize:PyObject**:unicode:0:
+PyUnicode_Resize:Py_ssize_t:length::
+
PyUnicode_Fill:Py_ssize_t:::
PyUnicode_Fill:PyObject*:unicode:0:
PyUnicode_Fill:Py_ssize_t:start::
@@ -2989,18 +3007,8 @@ Py_GetCompiler:const char*:::
Py_GetCopyright:const char*:::
-Py_GetExecPrefix:wchar_t*:::
-
-Py_GetPath:wchar_t*:::
-
Py_GetPlatform:const char*:::
-Py_GetPrefix:wchar_t*:::
-
-Py_GetProgramFullPath:wchar_t*:::
-
-Py_GetProgramName:wchar_t*:::
-
Py_GetVersion:const char*:::
Py_INCREF:void:::
diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat
index 59e7a31bc2ef06..e71a40e55e918c 100644
--- a/Doc/data/stable_abi.dat
+++ b/Doc/data/stable_abi.dat
@@ -323,7 +323,6 @@ func,PyImport_ImportFrozenModuleObject,3.7,,
func,PyImport_ImportModule,3.2,,
func,PyImport_ImportModuleLevel,3.2,,
func,PyImport_ImportModuleLevelObject,3.7,,
-func,PyImport_ImportModuleNoBlock,3.2,,
func,PyImport_ReloadModule,3.2,,
func,PyIndex_Check,3.8,,
type,PyInterpreterState,3.2,,opaque
@@ -362,6 +361,7 @@ func,PyLong_AsLong,3.2,,
func,PyLong_AsLongAndOverflow,3.2,,
func,PyLong_AsLongLong,3.2,,
func,PyLong_AsLongLongAndOverflow,3.2,,
+func,PyLong_AsNativeBytes,3.14,,
func,PyLong_AsSize_t,3.2,,
func,PyLong_AsSsize_t,3.2,,
func,PyLong_AsUInt32,3.14,,
@@ -376,6 +376,7 @@ func,PyLong_FromInt32,3.14,,
func,PyLong_FromInt64,3.14,,
func,PyLong_FromLong,3.2,,
func,PyLong_FromLongLong,3.2,,
+func,PyLong_FromNativeBytes,3.14,,
func,PyLong_FromSize_t,3.2,,
func,PyLong_FromSsize_t,3.2,,
func,PyLong_FromString,3.2,,
@@ -383,6 +384,7 @@ func,PyLong_FromUInt32,3.14,,
func,PyLong_FromUInt64,3.14,,
func,PyLong_FromUnsignedLong,3.2,,
func,PyLong_FromUnsignedLongLong,3.2,,
+func,PyLong_FromUnsignedNativeBytes,3.14,,
func,PyLong_FromVoidPtr,3.2,,
func,PyLong_GetInfo,3.2,,
data,PyLong_Type,3.2,,
@@ -582,6 +584,7 @@ func,PySequence_Contains,3.2,,
func,PySequence_Count,3.2,,
func,PySequence_DelItem,3.2,,
func,PySequence_DelSlice,3.2,,
+func,PySequence_Fast,3.2,,
func,PySequence_GetItem,3.2,,
func,PySequence_GetSlice,3.2,,
func,PySequence_In,3.2,,
@@ -736,11 +739,7 @@ func,PyUnicode_Append,3.2,,
func,PyUnicode_AppendAndDel,3.2,,
func,PyUnicode_AsASCIIString,3.2,,
func,PyUnicode_AsCharmapString,3.2,,
-func,PyUnicode_AsDecodedObject,3.2,,
-func,PyUnicode_AsDecodedUnicode,3.2,,
-func,PyUnicode_AsEncodedObject,3.2,,
func,PyUnicode_AsEncodedString,3.2,,
-func,PyUnicode_AsEncodedUnicode,3.2,,
func,PyUnicode_AsLatin1String,3.2,,
func,PyUnicode_AsMBCSString,3.7,on Windows,
func,PyUnicode_AsRawUnicodeEscapeString,3.2,,
@@ -858,13 +857,7 @@ func,Py_GetCompiler,3.2,,
func,Py_GetConstant,3.13,,
func,Py_GetConstantBorrowed,3.13,,
func,Py_GetCopyright,3.2,,
-func,Py_GetExecPrefix,3.2,,
-func,Py_GetPath,3.2,,
func,Py_GetPlatform,3.2,,
-func,Py_GetPrefix,3.2,,
-func,Py_GetProgramFullPath,3.2,,
-func,Py_GetProgramName,3.2,,
-func,Py_GetPythonHome,3.2,,
func,Py_GetRecursionLimit,3.2,,
func,Py_GetVersion,3.2,,
data,Py_HasFileSystemDefaultEncoding,3.2,,
diff --git a/Doc/deprecations/c-api-pending-removal-in-3.15.rst b/Doc/deprecations/c-api-pending-removal-in-3.15.rst
index 666a1622dd0b29..b87f0a5ecde06f 100644
--- a/Doc/deprecations/c-api-pending-removal-in-3.15.rst
+++ b/Doc/deprecations/c-api-pending-removal-in-3.15.rst
@@ -2,7 +2,7 @@ Pending removal in Python 3.15
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* The bundled copy of ``libmpdecimal``.
-* The :c:func:`PyImport_ImportModuleNoBlock`:
+* The :c:func:`!PyImport_ImportModuleNoBlock`:
Use :c:func:`PyImport_ImportModule` instead.
* :c:func:`PyWeakref_GetObject` and :c:func:`PyWeakref_GET_OBJECT`:
Use :c:func:`PyWeakref_GetRef` instead. The `pythoncapi-compat project
@@ -10,29 +10,39 @@ Pending removal in Python 3.15
:c:func:`PyWeakref_GetRef` on Python 3.12 and older.
* :c:type:`Py_UNICODE` type and the :c:macro:`!Py_UNICODE_WIDE` macro:
Use :c:type:`wchar_t` instead.
+* :c:func:`!PyUnicode_AsDecodedObject`:
+ Use :c:func:`PyCodec_Decode` instead.
+* :c:func:`!PyUnicode_AsDecodedUnicode`:
+ Use :c:func:`PyCodec_Decode` instead; Note that some codecs (for example, "base64")
+ may return a type other than :class:`str`, such as :class:`bytes`.
+* :c:func:`!PyUnicode_AsEncodedObject`:
+ Use :c:func:`PyCodec_Encode` instead.
+* :c:func:`!PyUnicode_AsEncodedUnicode`:
+ Use :c:func:`PyCodec_Encode` instead; Note that some codecs (for example, "base64")
+ may return a type other than :class:`bytes`, such as :class:`str`.
* Python initialization functions, deprecated in Python 3.13:
- * :c:func:`Py_GetPath`:
+ * :c:func:`!Py_GetPath`:
Use :c:func:`PyConfig_Get("module_search_paths") `
(:data:`sys.path`) instead.
- * :c:func:`Py_GetPrefix`:
+ * :c:func:`!Py_GetPrefix`:
Use :c:func:`PyConfig_Get("base_prefix") `
(:data:`sys.base_prefix`) instead. Use :c:func:`PyConfig_Get("prefix")
` (:data:`sys.prefix`) if :ref:`virtual environments
` need to be handled.
- * :c:func:`Py_GetExecPrefix`:
+ * :c:func:`!Py_GetExecPrefix`:
Use :c:func:`PyConfig_Get("base_exec_prefix") `
(:data:`sys.base_exec_prefix`) instead. Use
:c:func:`PyConfig_Get("exec_prefix") `
(:data:`sys.exec_prefix`) if :ref:`virtual environments ` need to
be handled.
- * :c:func:`Py_GetProgramFullPath`:
+ * :c:func:`!Py_GetProgramFullPath`:
Use :c:func:`PyConfig_Get("executable") `
(:data:`sys.executable`) instead.
- * :c:func:`Py_GetProgramName`:
+ * :c:func:`!Py_GetProgramName`:
Use :c:func:`PyConfig_Get("executable") `
(:data:`sys.executable`) instead.
- * :c:func:`Py_GetPythonHome`:
+ * :c:func:`!Py_GetPythonHome`:
Use :c:func:`PyConfig_Get("home") ` or the
:envvar:`PYTHONHOME` environment variable instead.
diff --git a/Doc/deprecations/c-api-pending-removal-in-future.rst b/Doc/deprecations/c-api-pending-removal-in-future.rst
index 1003047344a3cc..841d1b455b6bec 100644
--- a/Doc/deprecations/c-api-pending-removal-in-future.rst
+++ b/Doc/deprecations/c-api-pending-removal-in-future.rst
@@ -18,14 +18,6 @@ although there is currently no date scheduled for their removal.
Use :c:func:`PyOS_AfterFork_Child` instead.
* :c:func:`PySlice_GetIndicesEx`:
Use :c:func:`PySlice_Unpack` and :c:func:`PySlice_AdjustIndices` instead.
-* :c:func:`!PyUnicode_AsDecodedObject`:
- Use :c:func:`PyCodec_Decode` instead.
-* :c:func:`!PyUnicode_AsDecodedUnicode`:
- Use :c:func:`PyCodec_Decode` instead.
-* :c:func:`!PyUnicode_AsEncodedObject`:
- Use :c:func:`PyCodec_Encode` instead.
-* :c:func:`!PyUnicode_AsEncodedUnicode`:
- Use :c:func:`PyCodec_Encode` instead.
* :c:func:`PyUnicode_READY`:
Unneeded since Python 3.12
* :c:func:`!PyErr_Display`:
diff --git a/Doc/deprecations/index.rst b/Doc/deprecations/index.rst
index bac6e3f18d4594..d064f2bec42c22 100644
--- a/Doc/deprecations/index.rst
+++ b/Doc/deprecations/index.rst
@@ -5,6 +5,10 @@ Deprecations
.. include:: pending-removal-in-3.16.rst
+.. include:: pending-removal-in-3.17.rst
+
+.. include:: pending-removal-in-3.19.rst
+
.. include:: pending-removal-in-future.rst
C API deprecations
@@ -12,4 +16,6 @@ C API deprecations
.. include:: c-api-pending-removal-in-3.15.rst
+.. include:: c-api-pending-removal-in-3.18.rst
+
.. include:: c-api-pending-removal-in-future.rst
diff --git a/Doc/deprecations/pending-removal-in-3.14.rst b/Doc/deprecations/pending-removal-in-3.14.rst
index 6159fa48848285..9aac10840a663f 100644
--- a/Doc/deprecations/pending-removal-in-3.14.rst
+++ b/Doc/deprecations/pending-removal-in-3.14.rst
@@ -78,7 +78,7 @@ Pending removal in Python 3.14
:meth:`~pathlib.PurePath.relative_to`: passing additional arguments is
deprecated.
-* :mod:`pkgutil`: :func:`!pkgutil.find_loader` and :func:!pkgutil.get_loader`
+* :mod:`pkgutil`: :func:`!pkgutil.find_loader` and :func:`!pkgutil.get_loader`
now raise :exc:`DeprecationWarning`;
use :func:`importlib.util.find_spec` instead.
(Contributed by Nikita Sobolev in :gh:`97850`.)
diff --git a/Doc/deprecations/pending-removal-in-3.15.rst b/Doc/deprecations/pending-removal-in-3.15.rst
index 92297e1518004d..a76d06cce1278a 100644
--- a/Doc/deprecations/pending-removal-in-3.15.rst
+++ b/Doc/deprecations/pending-removal-in-3.15.rst
@@ -20,7 +20,7 @@ Pending removal in Python 3.15
* :mod:`http.server`:
- * The obsolete and rarely used :class:`~http.server.CGIHTTPRequestHandler`
+ * The obsolete and rarely used :class:`!CGIHTTPRequestHandler`
has been deprecated since Python 3.13.
No direct replacement exists.
*Anything* is better than CGI to interface
@@ -51,13 +51,13 @@ Pending removal in Python 3.15
* :mod:`platform`:
- * :func:`~platform.java_ver` has been deprecated since Python 3.13.
+ * :func:`!platform.java_ver` has been deprecated since Python 3.13.
This function is only useful for Jython support, has a confusing API,
and is largely untested.
* :mod:`sysconfig`:
- * The ``check_home`` argument of :func:`sysconfig.is_python_build` has been
+ * The *check_home* argument of :func:`sysconfig.is_python_build` has been
deprecated since Python 3.12.
* :mod:`threading`:
@@ -85,6 +85,13 @@ Pending removal in Python 3.15
has been deprecated since Python 3.13.
Use the class-based syntax or the functional syntax instead.
+ * When using the functional syntax of :class:`~typing.TypedDict`\s, failing
+ to pass a value to the *fields* parameter (``TD = TypedDict("TD")``) or
+ passing ``None`` (``TD = TypedDict("TD", None)``) has been deprecated
+ since Python 3.13.
+ Use ``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``
+ to create a TypedDict with zero field.
+
* The :func:`typing.no_type_check_decorator` decorator function
has been deprecated since Python 3.13.
After eight years in the :mod:`typing` module,
@@ -92,8 +99,7 @@ Pending removal in Python 3.15
* :mod:`wave`:
- * The :meth:`~wave.Wave_read.getmark`, :meth:`!setmark`,
- and :meth:`~wave.Wave_read.getmarkers` methods of
+ * The ``getmark()``, ``setmark()`` and ``getmarkers()`` methods of
the :class:`~wave.Wave_read` and :class:`~wave.Wave_write` classes
have been deprecated since Python 3.13.
diff --git a/Doc/deprecations/pending-removal-in-3.16.rst b/Doc/deprecations/pending-removal-in-3.16.rst
index b408a6d72febe0..cdd76ee693f31b 100644
--- a/Doc/deprecations/pending-removal-in-3.16.rst
+++ b/Doc/deprecations/pending-removal-in-3.16.rst
@@ -32,7 +32,6 @@ Pending removal in Python 3.16
* :class:`asyncio.WindowsProactorEventLoopPolicy`
* :func:`asyncio.get_event_loop_policy`
* :func:`asyncio.set_event_loop_policy`
- * :func:`asyncio.set_event_loop`
Users should use :func:`asyncio.run` or :class:`asyncio.Runner` with
*loop_factory* to use the desired event loop implementation.
@@ -62,6 +61,20 @@ Pending removal in Python 3.16
* Calling the Python implementation of :func:`functools.reduce` with *function*
or *sequence* as keyword arguments has been deprecated since Python 3.14.
+* :mod:`logging`:
+
+ Support for custom logging handlers with the *strm* argument is deprecated
+ and scheduled for removal in Python 3.16. Define handlers with the *stream*
+ argument instead. (Contributed by Mariusz Felisiak in :gh:`115032`.)
+
+* :mod:`mimetypes`:
+
+ * Valid extensions start with a '.' or are empty for
+ :meth:`mimetypes.MimeTypes.add_type`.
+ Undotted extensions are deprecated and will
+ raise a :exc:`ValueError` in Python 3.16.
+ (Contributed by Hugo van Kemenade in :gh:`75223`.)
+
* :mod:`shutil`:
* The :class:`!ExecError` exception
diff --git a/Doc/deprecations/pending-removal-in-3.17.rst b/Doc/deprecations/pending-removal-in-3.17.rst
new file mode 100644
index 00000000000000..370b98307e5228
--- /dev/null
+++ b/Doc/deprecations/pending-removal-in-3.17.rst
@@ -0,0 +1,10 @@
+Pending removal in Python 3.17
+------------------------------
+
+* :mod:`typing`:
+
+ - Before Python 3.14, old-style unions were implemented using the private class
+ ``typing._UnionGenericAlias``. This class is no longer needed for the implementation,
+ but it has been retained for backward compatibility, with removal scheduled for Python
+ 3.17. Users should use documented introspection helpers like :func:`typing.get_origin`
+ and :func:`typing.get_args` instead of relying on private implementation details.
diff --git a/Doc/deprecations/pending-removal-in-3.19.rst b/Doc/deprecations/pending-removal-in-3.19.rst
new file mode 100644
index 00000000000000..3936f63ca5b5af
--- /dev/null
+++ b/Doc/deprecations/pending-removal-in-3.19.rst
@@ -0,0 +1,8 @@
+Pending removal in Python 3.19
+------------------------------
+
+* :mod:`ctypes`:
+
+ * Implicitly switching to the MSVC-compatible struct layout by setting
+ :attr:`~ctypes.Structure._pack_` but not :attr:`~ctypes.Structure._layout_`
+ on non-Windows platforms.
diff --git a/Doc/deprecations/pending-removal-in-future.rst b/Doc/deprecations/pending-removal-in-future.rst
index 42dce518717a85..4c4a368baca955 100644
--- a/Doc/deprecations/pending-removal-in-future.rst
+++ b/Doc/deprecations/pending-removal-in-future.rst
@@ -13,8 +13,6 @@ although there is currently no date scheduled for their removal.
deprecated.
* The :class:`argparse.FileType` type converter is deprecated.
-* :mod:`array`'s ``'u'`` format code (:gh:`57281`)
-
* :mod:`builtins`:
* ``bool(NotImplemented)``.
@@ -49,6 +47,8 @@ although there is currently no date scheduled for their removal.
:data:`calendar.FEBRUARY`.
(Contributed by Prince Roshan in :gh:`103636`.)
+* :mod:`codecs`: use :func:`open` instead of :func:`codecs.open`. (:gh:`133038`)
+
* :attr:`codeobject.co_lnotab`: use the :meth:`codeobject.co_lines` method
instead.
@@ -111,9 +111,6 @@ although there is currently no date scheduled for their removal.
* ``ssl.TLSVersion.TLSv1``
* ``ssl.TLSVersion.TLSv1_1``
-* :func:`sysconfig.is_python_build` *check_home* parameter is deprecated and
- ignored.
-
* :mod:`threading` methods:
* :meth:`!threading.Condition.notifyAll`: use :meth:`~threading.Condition.notify_all`.
@@ -127,6 +124,11 @@ although there is currently no date scheduled for their removal.
* :class:`typing.Text` (:gh:`92332`).
+* The internal class ``typing._UnionGenericAlias`` is no longer used to implement
+ :class:`typing.Union`. To preserve compatibility with users using this private
+ class, a compatibility shim will be provided until at least Python 3.17. (Contributed by
+ Jelle Zijlstra in :gh:`105499`.)
+
* :class:`unittest.IsolatedAsyncioTestCase`: it is deprecated to return a value
that is not ``None`` from a test case.
@@ -151,3 +153,6 @@ although there is currently no date scheduled for their removal.
:class:`~xml.etree.ElementTree.Element` is deprecated. In a future release it
will always return ``True``. Prefer explicit ``len(elem)`` or
``elem is not None`` tests instead.
+
+* :func:`sys._clear_type_cache` is deprecated:
+ use :func:`sys._clear_internal_caches` instead.
diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst
index 20397dc5add5db..b777862da79f14 100644
--- a/Doc/extending/embedding.rst
+++ b/Doc/extending/embedding.rst
@@ -196,8 +196,8 @@ interesting part with respect to embedding Python starts with ::
After initializing the interpreter, the script is loaded using
:c:func:`PyImport_Import`. This routine needs a Python string as its argument,
-which is constructed using the :c:func:`PyUnicode_FromString` data conversion
-routine. ::
+which is constructed using the :c:func:`PyUnicode_DecodeFSDefault` data
+conversion routine. ::
pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */
diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst
index 7f57a3a6aac0ed..e3612f3a1875ca 100644
--- a/Doc/extending/newtypes.rst
+++ b/Doc/extending/newtypes.rst
@@ -70,22 +70,24 @@ object itself needs to be freed here as well. Here is an example of this
function::
static void
- newdatatype_dealloc(newdatatypeobject *obj)
+ newdatatype_dealloc(PyObject *op)
{
- free(obj->obj_UnderlyingDatatypePtr);
- Py_TYPE(obj)->tp_free((PyObject *)obj);
+ newdatatypeobject *self = (newdatatypeobject *) op;
+ free(self->obj_UnderlyingDatatypePtr);
+ Py_TYPE(self)->tp_free(self);
}
If your type supports garbage collection, the destructor should call
:c:func:`PyObject_GC_UnTrack` before clearing any member fields::
static void
- newdatatype_dealloc(newdatatypeobject *obj)
+ newdatatype_dealloc(PyObject *op)
{
- PyObject_GC_UnTrack(obj);
- Py_CLEAR(obj->other_obj);
+ newdatatypeobject *self = (newdatatypeobject *) op;
+ PyObject_GC_UnTrack(op);
+ Py_CLEAR(self->other_obj);
...
- Py_TYPE(obj)->tp_free((PyObject *)obj);
+ Py_TYPE(self)->tp_free(self);
}
.. index::
@@ -117,17 +119,19 @@ done. This can be done using the :c:func:`PyErr_Fetch` and
PyErr_Fetch(&err_type, &err_value, &err_traceback);
cbresult = PyObject_CallNoArgs(self->my_callback);
- if (cbresult == NULL)
- PyErr_WriteUnraisable(self->my_callback);
- else
+ if (cbresult == NULL) {
+ PyErr_WriteUnraisable(self->my_callback);
+ }
+ else {
Py_DECREF(cbresult);
+ }
/* This restores the saved exception state */
PyErr_Restore(err_type, err_value, err_traceback);
Py_DECREF(self->my_callback);
}
- Py_TYPE(obj)->tp_free((PyObject*)self);
+ Py_TYPE(self)->tp_free(self);
}
.. note::
@@ -168,10 +172,11 @@ representation of the instance for which it is called. Here is a simple
example::
static PyObject *
- newdatatype_repr(newdatatypeobject *obj)
+ newdatatype_repr(PyObject *op)
{
+ newdatatypeobject *self = (newdatatypeobject *) op;
return PyUnicode_FromFormat("Repr-ified_newdatatype{{size:%d}}",
- obj->obj_UnderlyingDatatypePtr->size);
+ self->obj_UnderlyingDatatypePtr->size);
}
If no :c:member:`~PyTypeObject.tp_repr` handler is specified, the interpreter will supply a
@@ -188,10 +193,11 @@ used instead.
Here is a simple example::
static PyObject *
- newdatatype_str(newdatatypeobject *obj)
+ newdatatype_str(PyObject *op)
{
+ newdatatypeobject *self = (newdatatypeobject *) op;
return PyUnicode_FromFormat("Stringified_newdatatype{{size:%d}}",
- obj->obj_UnderlyingDatatypePtr->size);
+ self->obj_UnderlyingDatatypePtr->size);
}
@@ -329,16 +335,16 @@ method of a class would be called.
Here is an example::
static PyObject *
- newdatatype_getattr(newdatatypeobject *obj, char *name)
+ newdatatype_getattr(PyObject *op, char *name)
{
- if (strcmp(name, "data") == 0)
- {
- return PyLong_FromLong(obj->data);
+ newdatatypeobject *self = (newdatatypeobject *) op;
+ if (strcmp(name, "data") == 0) {
+ return PyLong_FromLong(self->data);
}
PyErr_Format(PyExc_AttributeError,
"'%.100s' object has no attribute '%.400s'",
- Py_TYPE(obj)->tp_name, name);
+ Py_TYPE(self)->tp_name, name);
return NULL;
}
@@ -349,7 +355,7 @@ example that simply raises an exception; if this were really all you wanted, the
:c:member:`~PyTypeObject.tp_setattr` handler should be set to ``NULL``. ::
static int
- newdatatype_setattr(newdatatypeobject *obj, char *name, PyObject *v)
+ newdatatype_setattr(PyObject *op, char *name, PyObject *v)
{
PyErr_Format(PyExc_RuntimeError, "Read-only attribute: %s", name);
return -1;
@@ -379,8 +385,10 @@ Here is a sample implementation, for a datatype that is considered equal if the
size of an internal pointer is equal::
static PyObject *
- newdatatype_richcmp(newdatatypeobject *obj1, newdatatypeobject *obj2, int op)
+ newdatatype_richcmp(PyObject *lhs, PyObject *rhs, int op)
{
+ newdatatypeobject *obj1 = (newdatatypeobject *) lhs;
+ newdatatypeobject *obj2 = (newdatatypeobject *) rhs;
PyObject *result;
int c, size1, size2;
@@ -399,8 +407,7 @@ size of an internal pointer is equal::
case Py_GE: c = size1 >= size2; break;
}
result = c ? Py_True : Py_False;
- Py_INCREF(result);
- return result;
+ return Py_NewRef(result);
}
@@ -439,12 +446,14 @@ This function, if you choose to provide it, should return a hash number for an
instance of your data type. Here is a simple example::
static Py_hash_t
- newdatatype_hash(newdatatypeobject *obj)
+ newdatatype_hash(PyObject *op)
{
+ newdatatypeobject *self = (newdatatypeobject *) op;
Py_hash_t result;
- result = obj->some_size + 32767 * obj->some_number;
- if (result == -1)
- result = -2;
+ result = self->some_size + 32767 * self->some_number;
+ if (result == -1) {
+ result = -2;
+ }
return result;
}
@@ -478,8 +487,9 @@ This function takes three arguments:
Here is a toy ``tp_call`` implementation::
static PyObject *
- newdatatype_call(newdatatypeobject *obj, PyObject *args, PyObject *kwds)
+ newdatatype_call(PyObject *op, PyObject *args, PyObject *kwds)
{
+ newdatatypeobject *self = (newdatatypeobject *) op;
PyObject *result;
const char *arg1;
const char *arg2;
@@ -490,7 +500,7 @@ Here is a toy ``tp_call`` implementation::
}
result = PyUnicode_FromFormat(
"Returning -- value: [%d] arg1: [%s] arg2: [%s] arg3: [%s]\n",
- obj->obj_UnderlyingDatatypePtr->size,
+ self->obj_UnderlyingDatatypePtr->size,
arg1, arg2, arg3);
return result;
}
@@ -563,12 +573,12 @@ The only further addition is that ``tp_dealloc`` needs to clear any weak
references (by calling :c:func:`PyObject_ClearWeakRefs`)::
static void
- Trivial_dealloc(TrivialObject *self)
+ Trivial_dealloc(PyObject *op)
{
/* Clear weakrefs first before calling any destructors */
- PyObject_ClearWeakRefs((PyObject *) self);
+ PyObject_ClearWeakRefs(op);
/* ... remainder of destruction code omitted for brevity ... */
- Py_TYPE(self)->tp_free((PyObject *) self);
+ Py_TYPE(op)->tp_free(op);
}
diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst
index bcf938f117d148..3fc91841416d71 100644
--- a/Doc/extending/newtypes_tutorial.rst
+++ b/Doc/extending/newtypes_tutorial.rst
@@ -250,16 +250,17 @@ Because we now have data to manage, we have to be more careful about object
allocation and deallocation. At a minimum, we need a deallocation method::
static void
- Custom_dealloc(CustomObject *self)
+ Custom_dealloc(PyObject *op)
{
+ CustomObject *self = (CustomObject *) op;
Py_XDECREF(self->first);
Py_XDECREF(self->last);
- Py_TYPE(self)->tp_free((PyObject *) self);
+ Py_TYPE(self)->tp_free(self);
}
which is assigned to the :c:member:`~PyTypeObject.tp_dealloc` member::
- .tp_dealloc = (destructor) Custom_dealloc,
+ .tp_dealloc = Custom_dealloc,
This method first clears the reference counts of the two Python attributes.
:c:func:`Py_XDECREF` correctly handles the case where its argument is
@@ -270,11 +271,31 @@ the object's type might not be :class:`!CustomType`, because the object may
be an instance of a subclass.
.. note::
- The explicit cast to ``destructor`` above is needed because we defined
- ``Custom_dealloc`` to take a ``CustomObject *`` argument, but the ``tp_dealloc``
- function pointer expects to receive a ``PyObject *`` argument. Otherwise,
- the compiler will emit a warning. This is object-oriented polymorphism,
- in C!
+
+ The explicit cast to ``CustomObject *`` above is needed because we defined
+ ``Custom_dealloc`` to take a ``PyObject *`` argument, as the ``tp_dealloc``
+ function pointer expects to receive a ``PyObject *`` argument.
+ By assigning to the the ``tp_dealloc`` slot of a type, we declare
+ that it can only be called with instances of our ``CustomObject``
+ class, so the cast to ``(CustomObject *)`` is safe.
+ This is object-oriented polymorphism, in C!
+
+ In existing code, or in previous versions of this tutorial,
+ you might see similar functions take a pointer to the subtype
+ object structure (``CustomObject*``) directly, like this::
+
+ Custom_dealloc(CustomObject *self)
+ {
+ Py_XDECREF(self->first);
+ Py_XDECREF(self->last);
+ Py_TYPE(self)->tp_free((PyObject *) self);
+ }
+ ...
+ .tp_dealloc = (destructor) Custom_dealloc,
+
+ This does the same thing on all architectures that CPython
+ supports, but according to the C standard, it invokes
+ undefined behavior.
We want to make sure that the first and last names are initialized to empty
strings, so we provide a ``tp_new`` implementation::
@@ -352,8 +373,9 @@ We also define an initialization function which accepts arguments to provide
initial values for our instance::
static int
- Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
+ Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
{
+ CustomObject *self = (CustomObject *) op;
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL, *tmp;
@@ -379,7 +401,7 @@ initial values for our instance::
by filling the :c:member:`~PyTypeObject.tp_init` slot. ::
- .tp_init = (initproc) Custom_init,
+ .tp_init = Custom_init,
The :c:member:`~PyTypeObject.tp_init` slot is exposed in Python as the
:meth:`~object.__init__` method. It is used to initialize an object after it's
@@ -403,8 +425,8 @@ the new attribute values. We might be tempted, for example to assign the
But this would be risky. Our type doesn't restrict the type of the
``first`` member, so it could be any kind of object. It could have a
destructor that causes code to be executed that tries to access the
-``first`` member; or that destructor could release the
-:term:`Global interpreter Lock ` and let arbitrary code run in other
+``first`` member; or that destructor could detach the
+:term:`thread state ` and let arbitrary code run in other
threads that accesses and modifies our object.
To be paranoid and protect ourselves against this possibility, we almost
@@ -413,8 +435,8 @@ don't we have to do this?
* when we absolutely know that the reference count is greater than 1;
-* when we know that deallocation of the object [#]_ will neither release
- the :term:`GIL` nor cause any calls back into our type's code;
+* when we know that deallocation of the object [#]_ will neither detach
+ the :term:`thread state ` nor cause any calls back into our type's code;
* when decrementing a reference count in a :c:member:`~PyTypeObject.tp_dealloc`
handler on a type which doesn't support cyclic garbage collection [#]_.
@@ -451,8 +473,9 @@ We define a single method, :meth:`!Custom.name`, that outputs the objects name a
concatenation of the first and last names. ::
static PyObject *
- Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
+ Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))
{
+ CustomObject *self = (CustomObject *) op;
if (self->first == NULL) {
PyErr_SetString(PyExc_AttributeError, "first");
return NULL;
@@ -486,7 +509,7 @@ Now that we've defined the method, we need to create an array of method
definitions::
static PyMethodDef Custom_methods[] = {
- {"name", (PyCFunction) Custom_name, METH_NOARGS,
+ {"name", Custom_name, METH_NOARGS,
"Return the name, combining the first and last name"
},
{NULL} /* Sentinel */
@@ -543,15 +566,17 @@ we'll use custom getter and setter functions. Here are the functions for
getting and setting the :attr:`!first` attribute::
static PyObject *
- Custom_getfirst(CustomObject *self, void *closure)
+ Custom_getfirst(PyObject *op, void *closure)
{
+ CustomObject *self = (CustomObject *) op;
Py_INCREF(self->first);
return self->first;
}
static int
- Custom_setfirst(CustomObject *self, PyObject *value, void *closure)
+ Custom_setfirst(PyObject *op, PyObject *value, void *closure)
{
+ CustomObject *self = (CustomObject *) op;
PyObject *tmp;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
@@ -583,9 +608,9 @@ new value is not a string.
We create an array of :c:type:`PyGetSetDef` structures::
static PyGetSetDef Custom_getsetters[] = {
- {"first", (getter) Custom_getfirst, (setter) Custom_setfirst,
+ {"first", Custom_getfirst, Custom_setfirst,
"first name", NULL},
- {"last", (getter) Custom_getlast, (setter) Custom_setlast,
+ {"last", Custom_getlast, Custom_setlast,
"last name", NULL},
{NULL} /* Sentinel */
};
@@ -609,8 +634,9 @@ We also need to update the :c:member:`~PyTypeObject.tp_init` handler to only
allow strings [#]_ to be passed::
static int
- Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
+ Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
{
+ CustomObject *self = (CustomObject *) op;
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL, *tmp;
@@ -689,8 +715,9 @@ First, the traversal method lets the cyclic GC know about subobjects that could
participate in cycles::
static int
- Custom_traverse(CustomObject *self, visitproc visit, void *arg)
+ Custom_traverse(PyObject *op, visitproc visit, void *arg)
{
+ CustomObject *self = (CustomObject *) op;
int vret;
if (self->first) {
vret = visit(self->first, arg);
@@ -716,8 +743,9 @@ functions. With :c:func:`Py_VISIT`, we can minimize the amount of boilerplate
in ``Custom_traverse``::
static int
- Custom_traverse(CustomObject *self, visitproc visit, void *arg)
+ Custom_traverse(PyObject *op, visitproc visit, void *arg)
{
+ CustomObject *self = (CustomObject *) op;
Py_VISIT(self->first);
Py_VISIT(self->last);
return 0;
@@ -731,8 +759,9 @@ Second, we need to provide a method for clearing any subobjects that can
participate in cycles::
static int
- Custom_clear(CustomObject *self)
+ Custom_clear(PyObject *op)
{
+ CustomObject *self = (CustomObject *) op;
Py_CLEAR(self->first);
Py_CLEAR(self->last);
return 0;
@@ -765,11 +794,11 @@ Here is our reimplemented deallocator using :c:func:`PyObject_GC_UnTrack`
and ``Custom_clear``::
static void
- Custom_dealloc(CustomObject *self)
+ Custom_dealloc(PyObject *op)
{
- PyObject_GC_UnTrack(self);
- Custom_clear(self);
- Py_TYPE(self)->tp_free((PyObject *) self);
+ PyObject_GC_UnTrack(op);
+ (void)Custom_clear(op);
+ Py_TYPE(op)->tp_free(op);
}
Finally, we add the :c:macro:`Py_TPFLAGS_HAVE_GC` flag to the class flags::
@@ -825,9 +854,10 @@ When a Python object is a :class:`!SubList` instance, its ``PyObject *`` pointer
can be safely cast to both ``PyListObject *`` and ``SubListObject *``::
static int
- SubList_init(SubListObject *self, PyObject *args, PyObject *kwds)
+ SubList_init(PyObject *op, PyObject *args, PyObject *kwds)
{
- if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0)
+ SubListObject *self = (SubListObject *) op;
+ if (PyList_Type.tp_init(op, args, kwds) < 0)
return -1;
self->state = 0;
return 0;
diff --git a/Doc/extending/windows.rst b/Doc/extending/windows.rst
index e366d6cb9f79e3..56aa44e4e58c83 100644
--- a/Doc/extending/windows.rst
+++ b/Doc/extending/windows.rst
@@ -96,6 +96,13 @@ gives you access to spam's names, but does not create a separate copy. On Unix,
linking with a library is more like ``from spam import *``; it does create a
separate copy.
+.. c:macro:: Py_NO_LINK_LIB
+
+ Turn off the implicit, ``#pragma``-based linkage with the Python
+ library, performed inside CPython header files.
+
+ .. versionadded:: 3.14
+
.. _win-dlls:
@@ -108,21 +115,46 @@ Using DLLs in Practice
Windows Python is built in Microsoft Visual C++; using other compilers may or
may not work. The rest of this section is MSVC++ specific.
-When creating DLLs in Windows, you must pass :file:`pythonXY.lib` to the linker.
-To build two DLLs, spam and ni (which uses C functions found in spam), you could
-use these commands::
+When creating DLLs in Windows, you can use the CPython library in two ways:
+
+1. By default, inclusion of :file:`PC/pyconfig.h` directly or via
+ :file:`Python.h` triggers an implicit, configure-aware link with the
+ library. The header file chooses :file:`pythonXY_d.lib` for Debug,
+ :file:`pythonXY.lib` for Release, and :file:`pythonX.lib` for Release with
+ the `Limited API `_ enabled.
+
+ To build two DLLs, spam and ni (which uses C functions found in spam), you
+ could use these commands::
+
+ cl /LD /I/python/include spam.c
+ cl /LD /I/python/include ni.c spam.lib
+
+ The first command created three files: :file:`spam.obj`, :file:`spam.dll`
+ and :file:`spam.lib`. :file:`Spam.dll` does not contain any Python
+ functions (such as :c:func:`PyArg_ParseTuple`), but it does know how to find
+ the Python code thanks to the implicitly linked :file:`pythonXY.lib`.
+
+ The second command created :file:`ni.dll` (and :file:`.obj` and
+ :file:`.lib`), which knows how to find the necessary functions from spam,
+ and also from the Python executable.
+
+2. Manually by defining :c:macro:`Py_NO_LINK_LIB` macro before including
+ :file:`Python.h`. You must pass :file:`pythonXY.lib` to the linker.
+
+ To build two DLLs, spam and ni (which uses C functions found in spam), you
+ could use these commands::
- cl /LD /I/python/include spam.c ../libs/pythonXY.lib
- cl /LD /I/python/include ni.c spam.lib ../libs/pythonXY.lib
+ cl /LD /DPy_NO_LINK_LIB /I/python/include spam.c ../libs/pythonXY.lib
+ cl /LD /DPy_NO_LINK_LIB /I/python/include ni.c spam.lib ../libs/pythonXY.lib
-The first command created three files: :file:`spam.obj`, :file:`spam.dll` and
-:file:`spam.lib`. :file:`Spam.dll` does not contain any Python functions (such
-as :c:func:`PyArg_ParseTuple`), but it does know how to find the Python code
-thanks to :file:`pythonXY.lib`.
+ The first command created three files: :file:`spam.obj`, :file:`spam.dll`
+ and :file:`spam.lib`. :file:`Spam.dll` does not contain any Python
+ functions (such as :c:func:`PyArg_ParseTuple`), but it does know how to find
+ the Python code thanks to :file:`pythonXY.lib`.
-The second command created :file:`ni.dll` (and :file:`.obj` and :file:`.lib`),
-which knows how to find the necessary functions from spam, and also from the
-Python executable.
+ The second command created :file:`ni.dll` (and :file:`.obj` and
+ :file:`.lib`), which knows how to find the necessary functions from spam,
+ and also from the Python executable.
Not every identifier is exported to the lookup table. If you want any other
modules (including Python) to be able to see your identifiers, you have to say
diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst
index e2710fab9cf800..c758c019ca437b 100644
--- a/Doc/faq/design.rst
+++ b/Doc/faq/design.rst
@@ -420,10 +420,12 @@ strings representing the files in the current directory. Functions which
operate on this output would generally not break if you added another file or
two to the directory.
-Tuples are immutable, meaning that once a tuple has been created, you can't
-replace any of its elements with a new value. Lists are mutable, meaning that
-you can always change a list's elements. Only immutable elements can be used as
-dictionary keys, and hence only tuples and not lists can be used as keys.
+Tuples are :term:`immutable`, meaning that once a tuple has been created, you can't
+replace any of its elements with a new value. Lists are :term:`mutable`, meaning that
+you can always change a list's elements. Only :term:`hashable` objects can
+be used as dictionary keys. Most immutable types are hashable, which is why
+tuples, but not lists, can be used as keys. Note, however, that a tuple is
+only hashable if all of its elements are hashable.
How are lists implemented in CPython?
diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst
index 776bab1ed5b779..9f9e4fab685b19 100644
--- a/Doc/faq/programming.rst
+++ b/Doc/faq/programming.rst
@@ -986,8 +986,8 @@ There are various techniques.
f()
-Is there an equivalent to Perl's chomp() for removing trailing newlines from strings?
--------------------------------------------------------------------------------------
+Is there an equivalent to Perl's ``chomp()`` for removing trailing newlines from strings?
+-----------------------------------------------------------------------------------------
You can use ``S.rstrip("\r\n")`` to remove all occurrences of any line
terminator from the end of the string ``S`` without removing other trailing
@@ -1005,8 +1005,8 @@ Since this is typically only desired when reading text one line at a time, using
``S.rstrip()`` this way works well.
-Is there a scanf() or sscanf() equivalent?
-------------------------------------------
+Is there a ``scanf()`` or ``sscanf()`` equivalent?
+--------------------------------------------------
Not as such.
@@ -1020,8 +1020,8 @@ For more complicated input parsing, regular expressions are more powerful
than C's ``sscanf`` and better suited for the task.
-What does 'UnicodeDecodeError' or 'UnicodeEncodeError' error mean?
--------------------------------------------------------------------
+What does ``UnicodeDecodeError`` or ``UnicodeEncodeError`` error mean?
+----------------------------------------------------------------------
See the :ref:`unicode-howto`.
@@ -1036,7 +1036,7 @@ A raw string ending with an odd number of backslashes will escape the string's q
>>> r'C:\this\will\not\work\'
File "", line 1
r'C:\this\will\not\work\'
- ^
+ ^
SyntaxError: unterminated string literal (detected at line 1)
There are several workarounds for this. One is to use regular strings and double
@@ -1868,15 +1868,15 @@ object identity is assured. Generally, there are three circumstances where
identity is guaranteed:
1) Assignments create new names but do not change object identity. After the
-assignment ``new = old``, it is guaranteed that ``new is old``.
+ assignment ``new = old``, it is guaranteed that ``new is old``.
2) Putting an object in a container that stores object references does not
-change object identity. After the list assignment ``s[0] = x``, it is
-guaranteed that ``s[0] is x``.
+ change object identity. After the list assignment ``s[0] = x``, it is
+ guaranteed that ``s[0] is x``.
3) If an object is a singleton, it means that only one instance of that object
-can exist. After the assignments ``a = None`` and ``b = None``, it is
-guaranteed that ``a is b`` because ``None`` is a singleton.
+ can exist. After the assignments ``a = None`` and ``b = None``, it is
+ guaranteed that ``a is b`` because ``None`` is a singleton.
In most other circumstances, identity tests are inadvisable and equality tests
are preferred. In particular, identity tests should not be used to check
diff --git a/Doc/glossary.rst b/Doc/glossary.rst
index 7670bd859e282e..c5c7994f1262a9 100644
--- a/Doc/glossary.rst
+++ b/Doc/glossary.rst
@@ -132,6 +132,28 @@ Glossary
iterator's :meth:`~object.__anext__` method until it raises a
:exc:`StopAsyncIteration` exception. Introduced by :pep:`492`.
+ attached thread state
+
+ A :term:`thread state` that is active for the current OS thread.
+
+ When a :term:`thread state` is attached, the OS thread has
+ access to the full Python C API and can safely invoke the
+ bytecode interpreter.
+
+ Unless a function explicitly notes otherwise, attempting to call
+ the C API without an attached thread state will result in a fatal
+ error or undefined behavior. A thread state can be attached and detached
+ explicitly by the user through the C API, or implicitly by the runtime,
+ including during blocking C calls and by the bytecode interpreter in between
+ calls.
+
+ On most builds of Python, having an attached thread state implies that the
+ caller holds the :term:`GIL` for the current interpreter, so only
+ one OS thread can have an attached thread state at a given moment. In
+ :term:`free-threaded ` builds of Python, threads can concurrently
+ hold an attached thread state, allowing for true parallelism of the bytecode
+ interpreter.
+
attribute
A value associated with an object which is usually referenced by name
using dotted expressions.
@@ -333,6 +355,12 @@ Glossary
tasks (see :mod:`asyncio`) associate each task with a context which
becomes the current context whenever the task starts or resumes execution.
+ cyclic isolate
+ A subgroup of one or more objects that reference each other in a reference
+ cycle, but are not referenced by objects outside the group. The goal of
+ the :term:`cyclic garbage collector ` is to identify these groups and break the reference
+ cycles so that the memory can be reclaimed.
+
decorator
A function returning another function, usually applied as a function
transformation using the ``@wrapper`` syntax. Common examples for
@@ -622,6 +650,10 @@ Glossary
multi-threaded applications and makes it easier to use multi-core CPUs
efficiently. For more details, see :pep:`703`.
+ In prior versions of Python's C API, a function might declare that it
+ requires the GIL to be held in order to use it. This refers to having an
+ :term:`attached thread state`.
+
hash-based pyc
A bytecode cache file that uses the hash rather than the last-modified
time of the corresponding source file to determine its validity. See
@@ -719,7 +751,7 @@ Glossary
iterables include all sequence types (such as :class:`list`, :class:`str`,
and :class:`tuple`) and some non-sequence types like :class:`dict`,
:term:`file objects `, and objects of any classes you define
- with an :meth:`~iterator.__iter__` method or with a
+ with an :meth:`~object.__iter__` method or with a
:meth:`~object.__getitem__` method
that implements :term:`sequence` semantics.
@@ -800,6 +832,10 @@ Glossary
thread removes *key* from *mapping* after the test, but before the lookup.
This issue can be solved with locks or by using the EAFP approach.
+ lexical analyzer
+
+ Formal name for the *tokenizer*; see :term:`token`.
+
list
A built-in Python :term:`sequence`. Despite its name it is more akin
to an array in other languages than to a linked list since access to
@@ -1291,6 +1327,40 @@ Glossary
See also :term:`binary file` for a file object able to read and write
:term:`bytes-like objects `.
+ thread state
+
+ The information used by the :term:`CPython` runtime to run in an OS thread.
+ For example, this includes the current exception, if any, and the
+ state of the bytecode interpreter.
+
+ Each thread state is bound to a single OS thread, but threads may have
+ many thread states available. At most, one of them may be
+ :term:`attached ` at once.
+
+ An :term:`attached thread state` is required to call most
+ of Python's C API, unless a function explicitly documents otherwise.
+ The bytecode interpreter only runs under an attached thread state.
+
+ Each thread state belongs to a single interpreter, but each interpreter
+ may have many thread states, including multiple for the same OS thread.
+ Thread states from multiple interpreters may be bound to the same
+ thread, but only one can be :term:`attached ` in
+ that thread at any given moment.
+
+ See :ref:`Thread State and the Global Interpreter Lock ` for more
+ information.
+
+ token
+
+ A small unit of source code, generated by the
+ :ref:`lexical analyzer ` (also called the *tokenizer*).
+ Names, numbers, strings, operators,
+ newlines and similar are represented by tokens.
+
+ The :mod:`tokenize` module exposes Python's lexical analyzer.
+ The :mod:`token` module contains information on the various types
+ of tokens.
+
triple-quoted string
A string which is bound by three instances of either a quotation mark
(") or an apostrophe ('). While they don't provide any functionality
diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst
index f9ad81e38f8dc3..6994a5328e8149 100644
--- a/Doc/howto/curses.rst
+++ b/Doc/howto/curses.rst
@@ -145,8 +145,8 @@ importing the :func:`curses.wrapper` function and using it like this::
v = i-10
stdscr.addstr(i, 0, '10 divided by {} is {}'.format(v, 10/v))
- stdscr.refresh()
- stdscr.getkey()
+ stdscr.refresh()
+ stdscr.getkey()
wrapper(main)
diff --git a/Doc/howto/free-threading-extensions.rst b/Doc/howto/free-threading-extensions.rst
index 95f214179bfb0e..5a3970f15d52d6 100644
--- a/Doc/howto/free-threading-extensions.rst
+++ b/Doc/howto/free-threading-extensions.rst
@@ -23,6 +23,14 @@ You can use it to enable code that only runs under the free-threaded build::
/* code that only runs in the free-threaded build */
#endif
+.. note::
+
+ On Windows, this macro is not defined automatically, but must be specified
+ to the compiler when building. The :func:`sysconfig.get_config_var` function
+ can be used to determine whether the current running interpreter had the
+ macro defined.
+
+
Module Initialization
=====================
@@ -243,6 +251,141 @@ depend on your extension, but some common patterns include:
`thread-local storage `_.
+Critical Sections
+=================
+
+.. _critical-sections:
+
+In the free-threaded build, CPython provides a mechanism called "critical
+sections" to protect data that would otherwise be protected by the GIL.
+While extension authors may not interact with the internal critical section
+implementation directly, understanding their behavior is crucial when using
+certain C API functions or managing shared state in the free-threaded build.
+
+What Are Critical Sections?
+...........................
+
+Conceptually, critical sections act as a deadlock avoidance layer built on
+top of simple mutexes. Each thread maintains a stack of active critical
+sections. When a thread needs to acquire a lock associated with a critical
+section (e.g., implicitly when calling a thread-safe C API function like
+:c:func:`PyDict_SetItem`, or explicitly using macros), it attempts to acquire
+the underlying mutex.
+
+Using Critical Sections
+.......................
+
+The primary APIs for using critical sections are:
+
+* :c:macro:`Py_BEGIN_CRITICAL_SECTION` and :c:macro:`Py_END_CRITICAL_SECTION` -
+ For locking a single object
+
+* :c:macro:`Py_BEGIN_CRITICAL_SECTION2` and :c:macro:`Py_END_CRITICAL_SECTION2`
+ - For locking two objects simultaneously
+
+These macros must be used in matching pairs and must appear in the same C
+scope, since they establish a new local scope. These macros are no-ops in
+non-free-threaded builds, so they can be safely added to code that needs to
+support both build types.
+
+A common use of a critical section would be to lock an object while accessing
+an internal attribute of it. For example, if an extension type has an internal
+count field, you could use a critical section while reading or writing that
+field::
+
+ // read the count, returns new reference to internal count value
+ PyObject *result;
+ Py_BEGIN_CRITICAL_SECTION(obj);
+ result = Py_NewRef(obj->count);
+ Py_END_CRITICAL_SECTION();
+ return result;
+
+ // write the count, consumes reference from new_count
+ Py_BEGIN_CRITICAL_SECTION(obj);
+ obj->count = new_count;
+ Py_END_CRITICAL_SECTION();
+
+
+How Critical Sections Work
+..........................
+
+Unlike traditional locks, critical sections do not guarantee exclusive access
+throughout their entire duration. If a thread would block while holding a
+critical section (e.g., by acquiring another lock or performing I/O), the
+critical section is temporarily suspended—all locks are released—and then
+resumed when the blocking operation completes.
+
+This behavior is similar to what happens with the GIL when a thread makes a
+blocking call. The key differences are:
+
+* Critical sections operate on a per-object basis rather than globally
+
+* Critical sections follow a stack discipline within each thread (the "begin" and
+ "end" macros enforce this since they must be paired and within the same scope)
+
+* Critical sections automatically release and reacquire locks around potential
+ blocking operations
+
+Deadlock Avoidance
+..................
+
+Critical sections help avoid deadlocks in two ways:
+
+1. If a thread tries to acquire a lock that's already held by another thread,
+ it first suspends all of its active critical sections, temporarily releasing
+ their locks
+
+2. When the blocking operation completes, only the top-most critical section is
+ reacquired first
+
+This means you cannot rely on nested critical sections to lock multiple objects
+at once, as the inner critical section may suspend the outer ones. Instead, use
+:c:macro:`Py_BEGIN_CRITICAL_SECTION2` to lock two objects simultaneously.
+
+Note that the locks described above are only :c:type:`!PyMutex` based locks.
+The critical section implementation does not know about or affect other locking
+mechanisms that might be in use, like POSIX mutexes. Also note that while
+blocking on any :c:type:`!PyMutex` causes the critical sections to be
+suspended, only the mutexes that are part of the critical sections are
+released. If :c:type:`!PyMutex` is used without a critical section, it will
+not be released and therefore does not get the same deadlock avoidance.
+
+Important Considerations
+........................
+
+* Critical sections may temporarily release their locks, allowing other threads
+ to modify the protected data. Be careful about making assumptions about the
+ state of the data after operations that might block.
+
+* Because locks can be temporarily released (suspended), entering a critical
+ section does not guarantee exclusive access to the protected resource
+ throughout the section's duration. If code within a critical section calls
+ another function that blocks (e.g., acquires another lock, performs blocking
+ I/O), all locks held by the thread via critical sections will be released.
+ This is similar to how the GIL can be released during blocking calls.
+
+* Only the lock(s) associated with the most recently entered (top-most)
+ critical section are guaranteed to be held at any given time. Locks for
+ outer, nested critical sections might have been suspended.
+
+* You can lock at most two objects simultaneously with these APIs. If you need
+ to lock more objects, you'll need to restructure your code.
+
+* While critical sections will not deadlock if you attempt to lock the same
+ object twice, they are less efficient than purpose-built reentrant locks for
+ this use case.
+
+* When using :c:macro:`Py_BEGIN_CRITICAL_SECTION2`, the order of the objects
+ doesn't affect correctness (the implementation handles deadlock avoidance),
+ but it's good practice to always lock objects in a consistent order.
+
+* Remember that the critical section macros are primarily for protecting access
+ to *Python objects* that might be involved in internal CPython operations
+ susceptible to the deadlock scenarios described above. For protecting purely
+ internal extension state, standard mutexes or other synchronization
+ primitives might be more appropriate.
+
+
Building Extensions for the Free-Threaded Build
===============================================
diff --git a/Doc/howto/free-threading-python.rst b/Doc/howto/free-threading-python.rst
index cd920553a3a461..f7a894ac2cd78e 100644
--- a/Doc/howto/free-threading-python.rst
+++ b/Doc/howto/free-threading-python.rst
@@ -152,3 +152,33 @@ to re-enable it in a thread-safe way in the 3.14 release. This overhead is
expected to be reduced in upcoming Python release. We are aiming for an
overhead of 10% or less on the pyperformance suite compared to the default
GIL-enabled build.
+
+
+Behavioral changes
+==================
+
+This section describes CPython behavioural changes with the free-threaded
+build.
+
+
+Context variables
+-----------------
+
+In the free-threaded build, the flag :data:`~sys.flags.thread_inherit_context`
+is set to true by default which causes threads created with
+:class:`threading.Thread` to start with a copy of the
+:class:`~contextvars.Context()` of the caller of
+:meth:`~threading.Thread.start`. In the default GIL-enabled build, the flag
+defaults to false so threads start with an
+empty :class:`~contextvars.Context()`.
+
+
+Warning filters
+---------------
+
+In the free-threaded build, the flag :data:`~sys.flags.context_aware_warnings`
+is set to true by default. In the default GIL-enabled build, the flag defaults
+to false. If the flag is true then the :class:`warnings.catch_warnings`
+context manager uses a context variable for warning filters. If the flag is
+false then :class:`~warnings.catch_warnings` modifies the global filters list,
+which is not thread-safe. See the :mod:`warnings` module for more details.
diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst
index 1f0608fb0fc53f..b4f3463afee812 100644
--- a/Doc/howto/functional.rst
+++ b/Doc/howto/functional.rst
@@ -372,8 +372,8 @@ have the form::
for expr2 in sequence2
if condition2
for expr3 in sequence3
- ...
if condition3
+ ...
for exprN in sequenceN
if conditionN )
diff --git a/Doc/howto/index.rst b/Doc/howto/index.rst
index c09f92c9528ee1..f350141004c2db 100644
--- a/Doc/howto/index.rst
+++ b/Doc/howto/index.rst
@@ -34,6 +34,7 @@ Python Library Reference.
mro.rst
free-threading-python.rst
free-threading-extensions.rst
+ remote_debugging.rst
General:
@@ -66,3 +67,4 @@ Debugging and profiling:
* :ref:`gdb`
* :ref:`instrumentation`
* :ref:`perf_profiling`
+* :ref:`remote-debugging`
diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst
index f08f45179980f3..7d64a02358adb3 100644
--- a/Doc/howto/logging-cookbook.rst
+++ b/Doc/howto/logging-cookbook.rst
@@ -626,6 +626,19 @@ which, when run, will produce:
of each message with the handler's level, and only passes a message to a
handler if it's appropriate to do so.
+.. versionchanged:: 3.14
+ The :class:`QueueListener` can be started (and stopped) via the
+ :keyword:`with` statement. For example:
+
+ .. code-block:: python
+
+ with QueueListener(que, handler) as listener:
+ # The queue listener automatically starts
+ # when the 'with' block is entered.
+ pass
+ # The queue listener automatically stops once
+ # the 'with' block is exited.
+
.. _network-logging:
Sending and receiving logging events across a network
diff --git a/Doc/howto/perf_profiling.rst b/Doc/howto/perf_profiling.rst
index 06459d1b222964..b579d776576365 100644
--- a/Doc/howto/perf_profiling.rst
+++ b/Doc/howto/perf_profiling.rst
@@ -162,12 +162,12 @@ the :option:`!-X` option takes precedence over the environment variable.
Example, using the environment variable::
- $ PYTHONPERFSUPPORT=1 perf record -F 9999 -g -o perf.data python script.py
+ $ PYTHONPERFSUPPORT=1 perf record -F 9999 -g -o perf.data python my_script.py
$ perf report -g -i perf.data
Example, using the :option:`!-X` option::
- $ perf record -F 9999 -g -o perf.data python -X perf script.py
+ $ perf record -F 9999 -g -o perf.data python -X perf my_script.py
$ perf report -g -i perf.data
Example, using the :mod:`sys` APIs in file :file:`example.py`:
@@ -236,7 +236,7 @@ When using the perf JIT mode, you need an extra step before you can run ``perf
report``. You need to call the ``perf inject`` command to inject the JIT
information into the ``perf.data`` file.::
- $ perf record -F 9999 -g --call-graph dwarf -o perf.data python -Xperf_jit my_script.py
+ $ perf record -F 9999 -g -k 1 --call-graph dwarf -o perf.data python -Xperf_jit my_script.py
$ perf inject -i perf.data --jit --output perf.jit.data
$ perf report -g -i perf.jit.data
@@ -254,13 +254,28 @@ files in the current directory which are ELF images for all the JIT trampolines
that were created by Python.
.. warning::
- Notice that when using ``--call-graph dwarf`` the ``perf`` tool will take
+ When using ``--call-graph dwarf``, the ``perf`` tool will take
snapshots of the stack of the process being profiled and save the
- information in the ``perf.data`` file. By default the size of the stack dump
- is 8192 bytes but the user can change the size by passing the size after
- comma like ``--call-graph dwarf,4096``. The size of the stack dump is
- important because if the size is too small ``perf`` will not be able to
- unwind the stack and the output will be incomplete. On the other hand, if
- the size is too big, then ``perf`` won't be able to sample the process as
- frequently as it would like as the overhead will be higher.
+ information in the ``perf.data`` file. By default, the size of the stack dump
+ is 8192 bytes, but you can change the size by passing it after
+ a comma like ``--call-graph dwarf,16384``.
+ The size of the stack dump is important because if the size is too small
+ ``perf`` will not be able to unwind the stack and the output will be
+ incomplete. On the other hand, if the size is too big, then ``perf`` won't
+ be able to sample the process as frequently as it would like as the overhead
+ will be higher.
+
+ The stack size is particularly important when profiling Python code compiled
+ with low optimization levels (like ``-O0``), as these builds tend to have
+ larger stack frames. If you are compiling Python with ``-O0`` and not seeing
+ Python functions in your profiling output, try increasing the stack dump
+ size to 65528 bytes (the maximum)::
+
+ $ perf record -F 9999 -g -k 1 --call-graph dwarf,65528 -o perf.data python -Xperf_jit my_script.py
+
+ Different compilation flags can significantly impact stack sizes:
+
+ - Builds with ``-O0`` typically have much larger stack frames than those with ``-O1`` or higher
+ - Adding optimizations (``-O1``, ``-O2``, etc.) typically reduces stack size
+ - Frame pointers (``-fno-omit-frame-pointer``) generally provide more reliable stack unwinding
diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst
index 5e2f9a9d1837fe..e543f6d5657d79 100644
--- a/Doc/howto/regex.rst
+++ b/Doc/howto/regex.rst
@@ -738,9 +738,12 @@ given location, they can obviously be matched an infinite number of times.
different: ``\A`` still matches only at the beginning of the string, but ``^``
may match at any location inside the string that follows a newline character.
-``\Z``
+``\z``
Matches only at the end of the string.
+``\Z``
+ The same as ``\z``. For compatibility with old Python versions.
+
``\b``
Word boundary. This is a zero-width assertion that matches only at the
beginning or end of a word. A word is defined as a sequence of alphanumeric
diff --git a/Doc/howto/remote_debugging.rst b/Doc/howto/remote_debugging.rst
new file mode 100644
index 00000000000000..3adb6ad03e5445
--- /dev/null
+++ b/Doc/howto/remote_debugging.rst
@@ -0,0 +1,545 @@
+.. _remote-debugging:
+
+Remote debugging attachment protocol
+====================================
+
+This section describes the low-level protocol that enables external tools to
+inject and execute a Python script within a running CPython process.
+
+This mechanism forms the basis of the :func:`sys.remote_exec` function, which
+instructs a remote Python process to execute a ``.py`` file. However, this
+section does not document the usage of that function. Instead, it provides a
+detailed explanation of the underlying protocol, which takes as input the
+``pid`` of a target Python process and the path to a Python source file to be
+executed. This information supports independent reimplementation of the
+protocol, regardless of programming language.
+
+.. warning::
+
+ The execution of the injected script depends on the interpreter reaching a
+ safe evaluation point. As a result, execution may be delayed depending on
+ the runtime state of the target process.
+
+Once injected, the script is executed by the interpreter within the target
+process the next time a safe evaluation point is reached. This approach enables
+remote execution capabilities without modifying the behavior or structure of
+the running Python application.
+
+Subsequent sections provide a step-by-step description of the protocol,
+including techniques for locating interpreter structures in memory, safely
+accessing internal fields, and triggering code execution. Platform-specific
+variations are noted where applicable, and example implementations are included
+to clarify each operation.
+
+Locating the PyRuntime structure
+================================
+
+CPython places the ``PyRuntime`` structure in a dedicated binary section to
+help external tools find it at runtime. The name and format of this section
+vary by platform. For example, ``.PyRuntime`` is used on ELF systems, and
+``__DATA,__PyRuntime`` is used on macOS. Tools can find the offset of this
+structure by examining the binary on disk.
+
+The ``PyRuntime`` structure contains CPython’s global interpreter state and
+provides access to other internal data, including the list of interpreters,
+thread states, and debugger support fields.
+
+To work with a remote Python process, a debugger must first find the memory
+address of the ``PyRuntime`` structure in the target process. This address
+can’t be hardcoded or calculated from a symbol name, because it depends on
+where the operating system loaded the binary.
+
+The method for finding ``PyRuntime`` depends on the platform, but the steps are
+the same in general:
+
+1. Find the base address where the Python binary or shared library was loaded
+ in the target process.
+2. Use the on-disk binary to locate the offset of the ``.PyRuntime`` section.
+3. Add the section offset to the base address to compute the address in memory.
+
+The sections below explain how to do this on each supported platform and
+include example code.
+
+.. rubric:: Linux (ELF)
+
+To find the ``PyRuntime`` structure on Linux:
+
+1. Read the process’s memory map (for example, ``/proc//maps``) to find
+ the address where the Python executable or ``libpython`` was loaded.
+2. Parse the ELF section headers in the binary to get the offset of the
+ ``.PyRuntime`` section.
+3. Add that offset to the base address from step 1 to get the memory address of
+ ``PyRuntime``.
+
+The following is an example implementation::
+
+ def find_py_runtime_linux(pid: int) -> int:
+ # Step 1: Try to find the Python executable in memory
+ binary_path, base_address = find_mapped_binary(
+ pid, name_contains="python"
+ )
+
+ # Step 2: Fallback to shared library if executable is not found
+ if binary_path is None:
+ binary_path, base_address = find_mapped_binary(
+ pid, name_contains="libpython"
+ )
+
+ # Step 3: Parse ELF headers to get .PyRuntime section offset
+ section_offset = parse_elf_section_offset(
+ binary_path, ".PyRuntime"
+ )
+
+ # Step 4: Compute PyRuntime address in memory
+ return base_address + section_offset
+
+
+On Linux systems, there are two main approaches to read memory from another
+process. The first is through the ``/proc`` filesystem, specifically by reading from
+``/proc/[pid]/mem`` which provides direct access to the process's memory. This
+requires appropriate permissions - either being the same user as the target
+process or having root access. The second approach is using the
+``process_vm_readv()`` system call which provides a more efficient way to copy
+memory between processes. While ptrace's ``PTRACE_PEEKTEXT`` operation can also be
+used to read memory, it is significantly slower as it only reads one word at a
+time and requires multiple context switches between the tracer and tracee
+processes.
+
+For parsing ELF sections, the process involves reading and interpreting the ELF
+file format structures from the binary file on disk. The ELF header contains a
+pointer to the section header table. Each section header contains metadata about
+a section including its name (stored in a separate string table), offset, and
+size. To find a specific section like .PyRuntime, you need to walk through these
+headers and match the section name. The section header then provides the offset
+where that section exists in the file, which can be used to calculate its
+runtime address when the binary is loaded into memory.
+
+You can read more about the ELF file format in the `ELF specification
+`_.
+
+
+.. rubric:: macOS (Mach-O)
+
+To find the ``PyRuntime`` structure on macOS:
+
+1. Call ``task_for_pid()`` to get the ``mach_port_t`` task port for the target
+ process. This handle is needed to read memory using APIs like
+ ``mach_vm_read_overwrite`` and ``mach_vm_region``.
+2. Scan the memory regions to find the one containing the Python executable or
+ ``libpython``.
+3. Load the binary file from disk and parse the Mach-O headers to find the
+ section named ``PyRuntime`` in the ``__DATA`` segment. On macOS, symbol
+ names are automatically prefixed with an underscore, so the ``PyRuntime``
+ symbol appears as ``_PyRuntime`` in the symbol table, but the section name
+ is not affected.
+
+The following is an example implementation::
+
+ def find_py_runtime_macos(pid: int) -> int:
+ # Step 1: Get access to the process's memory
+ handle = get_memory_access_handle(pid)
+
+ # Step 2: Try to find the Python executable in memory
+ binary_path, base_address = find_mapped_binary(
+ handle, name_contains="python"
+ )
+
+ # Step 3: Fallback to libpython if the executable is not found
+ if binary_path is None:
+ binary_path, base_address = find_mapped_binary(
+ handle, name_contains="libpython"
+ )
+
+ # Step 4: Parse Mach-O headers to get __DATA,__PyRuntime section offset
+ section_offset = parse_macho_section_offset(
+ binary_path, "__DATA", "__PyRuntime"
+ )
+
+ # Step 5: Compute the PyRuntime address in memory
+ return base_address + section_offset
+
+On macOS, accessing another process's memory requires using Mach-O specific APIs
+and file formats. The first step is obtaining a ``task_port`` handle via
+``task_for_pid()``, which provides access to the target process's memory space.
+This handle enables memory operations through APIs like
+``mach_vm_read_overwrite()``.
+
+The process memory can be examined using ``mach_vm_region()`` to scan through the
+virtual memory space, while ``proc_regionfilename()`` helps identify which binary
+files are loaded at each memory region. When the Python binary or library is
+found, its Mach-O headers need to be parsed to locate the ``PyRuntime`` structure.
+
+The Mach-O format organizes code and data into segments and sections. The
+``PyRuntime`` structure lives in a section named ``__PyRuntime`` within the
+``__DATA`` segment. The actual runtime address calculation involves finding the
+``__TEXT`` segment which serves as the binary's base address, then locating the
+``__DATA`` segment containing our target section. The final address is computed by
+combining the base address with the appropriate section offsets from the Mach-O
+headers.
+
+Note that accessing another process's memory on macOS typically requires
+elevated privileges - either root access or special security entitlements
+granted to the debugging process.
+
+
+.. rubric:: Windows (PE)
+
+To find the ``PyRuntime`` structure on Windows:
+
+1. Use the ToolHelp API to enumerate all modules loaded in the target process.
+ This is done using functions such as `CreateToolhelp32Snapshot
+ `_,
+ `Module32First
+ `_,
+ and `Module32Next
+ `_.
+2. Identify the module corresponding to :file:`python.exe` or
+ :file:`python{XY}.dll`, where ``X`` and ``Y`` are the major and minor
+ version numbers of the Python version, and record its base address.
+3. Locate the ``PyRuntim`` section. Due to the PE format's 8-character limit
+ on section names (defined as ``IMAGE_SIZEOF_SHORT_NAME``), the original
+ name ``PyRuntime`` is truncated. This section contains the ``PyRuntime``
+ structure.
+4. Retrieve the section’s relative virtual address (RVA) and add it to the base
+ address of the module.
+
+The following is an example implementation::
+
+ def find_py_runtime_windows(pid: int) -> int:
+ # Step 1: Try to find the Python executable in memory
+ binary_path, base_address = find_loaded_module(
+ pid, name_contains="python"
+ )
+
+ # Step 2: Fallback to shared pythonXY.dll if the executable is not
+ # found
+ if binary_path is None:
+ binary_path, base_address = find_loaded_module(
+ pid, name_contains="python3"
+ )
+
+ # Step 3: Parse PE section headers to get the RVA of the PyRuntime
+ # section. The section name appears as "PyRuntim" due to the
+ # 8-character limit defined by the PE format (IMAGE_SIZEOF_SHORT_NAME).
+ section_rva = parse_pe_section_offset(binary_path, "PyRuntim")
+
+ # Step 4: Compute PyRuntime address in memory
+ return base_address + section_rva
+
+
+On Windows, accessing another process's memory requires using the Windows API
+functions like ``CreateToolhelp32Snapshot()`` and ``Module32First()/Module32Next()``
+to enumerate loaded modules. The ``OpenProcess()`` function provides a handle to
+access the target process's memory space, enabling memory operations through
+``ReadProcessMemory()``.
+
+The process memory can be examined by enumerating loaded modules to find the
+Python binary or DLL. When found, its PE headers need to be parsed to locate the
+``PyRuntime`` structure.
+
+The PE format organizes code and data into sections. The ``PyRuntime`` structure
+lives in a section named "PyRuntim" (truncated from "PyRuntime" due to PE's
+8-character name limit). The actual runtime address calculation involves finding
+the module's base address from the module entry, then locating our target
+section in the PE headers. The final address is computed by combining the base
+address with the section's virtual address from the PE section headers.
+
+Note that accessing another process's memory on Windows typically requires
+appropriate privileges - either administrative access or the ``SeDebugPrivilege``
+privilege granted to the debugging process.
+
+
+Reading _Py_DebugOffsets
+========================
+
+Once the address of the ``PyRuntime`` structure has been determined, the next
+step is to read the ``_Py_DebugOffsets`` structure located at the beginning of
+the ``PyRuntime`` block.
+
+This structure provides version-specific field offsets that are needed to
+safely read interpreter and thread state memory. These offsets vary between
+CPython versions and must be checked before use to ensure they are compatible.
+
+To read and check the debug offsets, follow these steps:
+
+1. Read memory from the target process starting at the ``PyRuntime`` address,
+ covering the same number of bytes as the ``_Py_DebugOffsets`` structure.
+ This structure is located at the very start of the ``PyRuntime`` memory
+ block. Its layout is defined in CPython’s internal headers and stays the
+ same within a given minor version, but may change in major versions.
+
+2. Check that the structure contains valid data:
+
+ - The ``cookie`` field must match the expected debug marker.
+ - The ``version`` field must match the version of the Python interpreter
+ used by the debugger.
+ - If either the debugger or the target process is using a pre-release
+ version (for example, an alpha, beta, or release candidate), the versions
+ must match exactly.
+ - The ``free_threaded`` field must have the same value in both the debugger
+ and the target process.
+
+3. If the structure is valid, the offsets it contains can be used to locate
+ fields in memory. If any check fails, the debugger should stop the operation
+ to avoid reading memory in the wrong format.
+
+The following is an example implementation that reads and checks
+``_Py_DebugOffsets``::
+
+ def read_debug_offsets(pid: int, py_runtime_addr: int) -> DebugOffsets:
+ # Step 1: Read memory from the target process at the PyRuntime address
+ data = read_process_memory(
+ pid, address=py_runtime_addr, size=DEBUG_OFFSETS_SIZE
+ )
+
+ # Step 2: Deserialize the raw bytes into a _Py_DebugOffsets structure
+ debug_offsets = parse_debug_offsets(data)
+
+ # Step 3: Validate the contents of the structure
+ if debug_offsets.cookie != EXPECTED_COOKIE:
+ raise RuntimeError("Invalid or missing debug cookie")
+ if debug_offsets.version != LOCAL_PYTHON_VERSION:
+ raise RuntimeError(
+ "Mismatch between caller and target Python versions"
+ )
+ if debug_offsets.free_threaded != LOCAL_FREE_THREADED:
+ raise RuntimeError("Mismatch in free-threaded configuration")
+
+ return debug_offsets
+
+
+
+.. warning::
+
+ **Process suspension recommended**
+
+ To avoid race conditions and ensure memory consistency, it is strongly
+ recommended that the target process be suspended before performing any
+ operations that read or write internal interpreter state. The Python runtime
+ may concurrently mutate interpreter data structures—such as creating or
+ destroying threads—during normal execution. This can result in invalid
+ memory reads or writes.
+
+ A debugger may suspend execution by attaching to the process with ``ptrace``
+ or by sending a ``SIGSTOP`` signal. Execution should only be resumed after
+ debugger-side memory operations are complete.
+
+ .. note::
+
+ Some tools, such as profilers or sampling-based debuggers, may operate on
+ a running process without suspension. In such cases, tools must be
+ explicitly designed to handle partially updated or inconsistent memory.
+ For most debugger implementations, suspending the process remains the
+ safest and most robust approach.
+
+
+Locating the interpreter and thread state
+=========================================
+
+Before code can be injected and executed in a remote Python process, the
+debugger must choose a thread in which to schedule execution. This is necessary
+because the control fields used to perform remote code injection are located in
+the ``_PyRemoteDebuggerSupport`` structure, which is embedded in a
+``PyThreadState`` object. These fields are modified by the debugger to request
+execution of injected scripts.
+
+The ``PyThreadState`` structure represents a thread running inside a Python
+interpreter. It maintains the thread’s evaluation context and contains the
+fields required for debugger coordination. Locating a valid ``PyThreadState``
+is therefore a key prerequisite for triggering execution remotely.
+
+A thread is typically selected based on its role or ID. In most cases, the main
+thread is used, but some tools may target a specific thread by its native
+thread ID. Once the target thread is chosen, the debugger must locate both the
+interpreter and the associated thread state structures in memory.
+
+The relevant internal structures are defined as follows:
+
+- ``PyInterpreterState`` represents an isolated Python interpreter instance.
+ Each interpreter maintains its own set of imported modules, built-in state,
+ and thread state list. Although most Python applications use a single
+ interpreter, CPython supports multiple interpreters in the same process.
+
+- ``PyThreadState`` represents a thread running within an interpreter. It
+ contains execution state and the control fields used by the debugger.
+
+To locate a thread:
+
+1. Use the offset ``runtime_state.interpreters_head`` to obtain the address of
+ the first interpreter in the ``PyRuntime`` structure. This is the entry point
+ to the linked list of active interpreters.
+
+2. Use the offset ``interpreter_state.threads_main`` to access the main thread
+ state associated with the selected interpreter. This is typically the most
+ reliable thread to target.
+
+3. Optionally, use the offset ``interpreter_state.threads_head`` to iterate
+through the linked list of all thread states. Each ``PyThreadState`` structure
+contains a ``native_thread_id`` field, which may be compared to a target thread
+ID to find a specific thread.
+
+1. Once a valid ``PyThreadState`` has been found, its address can be used in
+later steps of the protocol, such as writing debugger control fields and
+scheduling execution.
+
+The following is an example implementation that locates the main thread state::
+
+ def find_main_thread_state(
+ pid: int, py_runtime_addr: int, debug_offsets: DebugOffsets,
+ ) -> int:
+ # Step 1: Read interpreters_head from PyRuntime
+ interp_head_ptr = (
+ py_runtime_addr + debug_offsets.runtime_state.interpreters_head
+ )
+ interp_addr = read_pointer(pid, interp_head_ptr)
+ if interp_addr == 0:
+ raise RuntimeError("No interpreter found in the target process")
+
+ # Step 2: Read the threads_main pointer from the interpreter
+ threads_main_ptr = (
+ interp_addr + debug_offsets.interpreter_state.threads_main
+ )
+ thread_state_addr = read_pointer(pid, threads_main_ptr)
+ if thread_state_addr == 0:
+ raise RuntimeError("Main thread state is not available")
+
+ return thread_state_addr
+
+The following example demonstrates how to locate a thread by its native thread
+ID::
+
+ def find_thread_by_id(
+ pid: int,
+ interp_addr: int,
+ debug_offsets: DebugOffsets,
+ target_tid: int,
+ ) -> int:
+ # Start at threads_head and walk the linked list
+ thread_ptr = read_pointer(
+ pid,
+ interp_addr + debug_offsets.interpreter_state.threads_head
+ )
+
+ while thread_ptr:
+ native_tid_ptr = (
+ thread_ptr + debug_offsets.thread_state.native_thread_id
+ )
+ native_tid = read_int(pid, native_tid_ptr)
+ if native_tid == target_tid:
+ return thread_ptr
+ thread_ptr = read_pointer(
+ pid,
+ thread_ptr + debug_offsets.thread_state.next
+ )
+
+ raise RuntimeError("Thread with the given ID was not found")
+
+
+Once a valid thread state has been located, the debugger can proceed with
+modifying its control fields and scheduling execution, as described in the next
+section.
+
+Writing control information
+===========================
+
+Once a valid ``PyThreadState`` structure has been identified, the debugger may
+modify control fields within it to schedule the execution of a specified Python
+script. These control fields are checked periodically by the interpreter, and
+when set correctly, they trigger the execution of remote code at a safe point
+in the evaluation loop.
+
+Each ``PyThreadState`` contains a ``_PyRemoteDebuggerSupport`` structure used
+for communication between the debugger and the interpreter. The locations of
+its fields are defined by the ``_Py_DebugOffsets`` structure and include the
+following:
+
+- ``debugger_script_path``: A fixed-size buffer that holds the full path to a
+ Python source file (``.py``). This file must be accessible and readable by
+ the target process when execution is triggered.
+
+- ``debugger_pending_call``: An integer flag. Setting this to ``1`` tells the
+ interpreter that a script is ready to be executed.
+
+- ``eval_breaker``: A field checked by the interpreter during execution.
+ Setting bit 5 (``_PY_EVAL_PLEASE_STOP_BIT``, value ``1U << 5``) in this
+ field causes the interpreter to pause and check for debugger activity.
+
+To complete the injection, the debugger must perform the following steps:
+
+1. Write the full script path into the ``debugger_script_path`` buffer.
+2. Set ``debugger_pending_call`` to ``1``.
+3. Read the current value of ``eval_breaker``, set bit 5
+ (``_PY_EVAL_PLEASE_STOP_BIT``), and write the updated value back. This
+ signals the interpreter to check for debugger activity.
+
+The following is an example implementation::
+
+ def inject_script(
+ pid: int,
+ thread_state_addr: int,
+ debug_offsets: DebugOffsets,
+ script_path: str
+ ) -> None:
+ # Compute the base offset of _PyRemoteDebuggerSupport
+ support_base = (
+ thread_state_addr +
+ debug_offsets.debugger_support.remote_debugger_support
+ )
+
+ # Step 1: Write the script path into debugger_script_path
+ script_path_ptr = (
+ support_base +
+ debug_offsets.debugger_support.debugger_script_path
+ )
+ write_string(pid, script_path_ptr, script_path)
+
+ # Step 2: Set debugger_pending_call to 1
+ pending_ptr = (
+ support_base +
+ debug_offsets.debugger_support.debugger_pending_call
+ )
+ write_int(pid, pending_ptr, 1)
+
+ # Step 3: Set _PY_EVAL_PLEASE_STOP_BIT (bit 5, value 1 << 5) in
+ # eval_breaker
+ eval_breaker_ptr = (
+ thread_state_addr +
+ debug_offsets.debugger_support.eval_breaker
+ )
+ breaker = read_int(pid, eval_breaker_ptr)
+ breaker |= (1 << 5)
+ write_int(pid, eval_breaker_ptr, breaker)
+
+
+Once these fields are set, the debugger may resume the process (if it was
+suspended). The interpreter will process the request at the next safe
+evaluation point, load the script from disk, and execute it.
+
+It is the responsibility of the debugger to ensure that the script file remains
+present and accessible to the target process during execution.
+
+.. note::
+
+ Script execution is asynchronous. The script file cannot be deleted
+ immediately after injection. The debugger should wait until the injected
+ script has produced an observable effect before removing the file.
+ This effect depends on what the script is designed to do. For example,
+ a debugger might wait until the remote process connects back to a socket
+ before removing the script. Once such an effect is observed, it is safe to
+ assume the file is no longer needed.
+
+Summary
+=======
+
+To inject and execute a Python script in a remote process:
+
+1. Locate the ``PyRuntime`` structure in the target process’s memory.
+2. Read and validate the ``_Py_DebugOffsets`` structure at the beginning of
+ ``PyRuntime``.
+3. Use the offsets to locate a valid ``PyThreadState``.
+4. Write the path to a Python script into ``debugger_script_path``.
+5. Set the ``debugger_pending_call`` flag to ``1``.
+6. Set ``_PY_EVAL_PLEASE_STOP_BIT`` in the ``eval_breaker`` field.
+7. Resume the process (if suspended). The script will execute at the next safe
+ evaluation point.
+
diff --git a/Doc/includes/email-alternative.py b/Doc/includes/email-alternative.py
index 26b302b495c7ac..afe2b4fbb5eb3f 100644
--- a/Doc/includes/email-alternative.py
+++ b/Doc/includes/email-alternative.py
@@ -36,7 +36,7 @@
recette
sera sûrement un très bon repas.
-
+