mirror of
https://github.com/python/cpython.git
synced 2026-05-04 09:31:02 +00:00
Merge remote-tracking branch 'origin/main' into pairwise_ft_v3
# Conflicts: # Lib/test/test_free_threading/test_itertools.py # Modules/itertoolsmodule.c
This commit is contained in:
commit
78eabbc87d
1639 changed files with 109108 additions and 43404 deletions
4
.gitattributes
vendored
4
.gitattributes
vendored
|
|
@ -34,6 +34,9 @@ Lib/test/xmltestdata/* noeol
|
|||
Lib/venv/scripts/common/activate text eol=lf
|
||||
Lib/venv/scripts/posix/* text eol=lf
|
||||
|
||||
# Prevent GitHub's web conflict editor from converting LF to CRLF
|
||||
*.rst text eol=lf
|
||||
|
||||
# CRLF files
|
||||
[attr]dos text eol=crlf
|
||||
|
||||
|
|
@ -112,3 +115,4 @@ Tools/peg_generator/pegen/grammar_parser.py generated
|
|||
aclocal.m4 generated
|
||||
configure generated
|
||||
*.min.js generated
|
||||
package-lock.json generated
|
||||
|
|
|
|||
98
.github/CODEOWNERS
vendored
98
.github/CODEOWNERS
vendored
|
|
@ -63,9 +63,10 @@
|
|||
.azure-pipelines/ @AA-Turner
|
||||
|
||||
# GitHub & related scripts
|
||||
.github/ @ezio-melotti @hugovk @AA-Turner @webknjaz
|
||||
Tools/build/compute-changes.py @AA-Turner @hugovk @webknjaz
|
||||
Tools/build/verify_ensurepip_wheels.py @AA-Turner @pfmoore @pradyunsg
|
||||
.github/ @ezio-melotti @hugovk @AA-Turner @webknjaz
|
||||
Tools/build/compute-changes.py @AA-Turner @hugovk @webknjaz
|
||||
Lib/test/test_tools/test_compute_changes.py @AA-Turner @hugovk @webknjaz
|
||||
Tools/build/verify_ensurepip_wheels.py @AA-Turner @pfmoore @pradyunsg
|
||||
|
||||
# Pre-commit
|
||||
.pre-commit-config.yaml @hugovk
|
||||
|
|
@ -99,17 +100,18 @@ Lib/test/test_build_details.py @FFY00
|
|||
InternalDocs/ @AA-Turner
|
||||
|
||||
# Tools, Configuration, etc
|
||||
Doc/Makefile @AA-Turner @hugovk
|
||||
Doc/_static/ @AA-Turner @hugovk
|
||||
Doc/conf.py @AA-Turner @hugovk
|
||||
Doc/make.bat @AA-Turner @hugovk
|
||||
Doc/requirements.txt @AA-Turner @hugovk
|
||||
Doc/tools/ @AA-Turner @hugovk
|
||||
Doc/Makefile @AA-Turner @hugovk @StanFromIreland
|
||||
Doc/_static/ @AA-Turner @hugovk @StanFromIreland
|
||||
Doc/conf.py @AA-Turner @hugovk @StanFromIreland
|
||||
Doc/make.bat @AA-Turner @hugovk @StanFromIreland
|
||||
Doc/requirements.txt @AA-Turner @hugovk @StanFromIreland
|
||||
Doc/tools/ @AA-Turner @hugovk @StanFromIreland
|
||||
|
||||
# PR Previews
|
||||
.readthedocs.yml @AA-Turner
|
||||
|
||||
# Sections
|
||||
Doc/c-api/ @ZeroIntensity
|
||||
Doc/reference/ @willingc @AA-Turner
|
||||
Doc/whatsnew/ @AA-Turner
|
||||
|
||||
|
|
@ -130,7 +132,9 @@ Tools/c-analyzer/ @ericsnowcurrently
|
|||
Tools/check-c-api-docs/ @ZeroIntensity
|
||||
|
||||
# Fuzzing
|
||||
Modules/_xxtestfuzz/ @ammaraskar
|
||||
Modules/_xxtestfuzz/ @python/fuzzers
|
||||
Lib/test/test_xxtestfuzz.py @python/fuzzers
|
||||
.github/workflows/reusable-cifuzz.yml @python/fuzzers
|
||||
|
||||
# Limited C API & Stable ABI
|
||||
Doc/c-api/stable.rst @encukou
|
||||
|
|
@ -258,40 +262,46 @@ Include/pyhash.h @gpshead @picnixz
|
|||
Python/pyhash.c @gpshead @picnixz
|
||||
|
||||
# The import system (including importlib)
|
||||
**/*import* @brettcannon @ericsnowcurrently @ncoghlan @warsaw
|
||||
Python/import.c @brettcannon @ericsnowcurrently @ncoghlan @warsaw @kumaraditya303
|
||||
**/*import* @brettcannon @ericsnowcurrently @ncoghlan @warsaw @FFY00
|
||||
Python/import.c @brettcannon @ericsnowcurrently @ncoghlan @warsaw @FFY00 @kumaraditya303
|
||||
**/*freeze* @ericsnowcurrently
|
||||
**/*frozen* @ericsnowcurrently
|
||||
**/*modsupport* @ericsnowcurrently
|
||||
**/*modulefinder* @ericsnowcurrently
|
||||
**/*modulefinder* @ericsnowcurrently @FFY00
|
||||
**/*moduleobject* @ericsnowcurrently
|
||||
**/*multiphase* @ericsnowcurrently
|
||||
**/*pkgutil* @ericsnowcurrently
|
||||
**/*pkgutil* @ericsnowcurrently @FFY00
|
||||
**/*pythonrun* @ericsnowcurrently
|
||||
**/*runpy* @ericsnowcurrently
|
||||
**/*runpy* @ericsnowcurrently @FFY00
|
||||
**/*singlephase* @ericsnowcurrently
|
||||
Doc/c-api/module.rst @ericsnowcurrently
|
||||
Lib/test/test_module/ @ericsnowcurrently
|
||||
Python/dynload_*.c @ericsnowcurrently
|
||||
Python/dynload_*.c @ericsnowcurrently @FFY00
|
||||
|
||||
# Initialisation
|
||||
**/*initconfig* @ericsnowcurrently
|
||||
**/*pathconfig* @ericsnowcurrently
|
||||
**/*preconfig* @ericsnowcurrently
|
||||
**/*initconfig* @ericsnowcurrently @FFY00
|
||||
**/*pathconfig* @ericsnowcurrently @FFY00
|
||||
**/*preconfig* @ericsnowcurrently @FFY00
|
||||
Doc/library/sys_path_init.rst @FFY00
|
||||
Doc/c-api/init_config.rst @FFY00
|
||||
|
||||
# Interpreter main program
|
||||
Modules/main.c @ericsnowcurrently
|
||||
Programs/_bootstrap_python.c @ericsnowcurrently
|
||||
Programs/python.c @ericsnowcurrently
|
||||
Modules/main.c @ericsnowcurrently @FFY00
|
||||
Programs/_bootstrap_python.c @ericsnowcurrently @FFY00
|
||||
Programs/python.c @ericsnowcurrently @FFY00
|
||||
|
||||
# JIT
|
||||
.github/workflows/jit.yml @savannahostrowski
|
||||
Include/internal/pycore_jit.h @brandtbucher @savannahostrowski @diegorusso
|
||||
Python/jit.c @brandtbucher @savannahostrowski @diegorusso
|
||||
Tools/jit/ @brandtbucher @savannahostrowski @diegorusso
|
||||
InternalDocs/jit.md @brandtbucher @savannahostrowski @diegorusso @AA-Turner
|
||||
|
||||
# Lazy imports (PEP 810)
|
||||
Objects/lazyimportobject.c @yhg1s @DinoV @pablogsal
|
||||
Include/internal/pycore_lazyimportobject.h @yhg1s @DinoV @pablogsal
|
||||
Lib/test/test_lazy_import @yhg1s @DinoV @pablogsal
|
||||
|
||||
# Micro-op / μop / Tier 2 Optimiser
|
||||
Python/optimizer.c @markshannon @Fidget-Spinner
|
||||
Python/optimizer_analysis.c @markshannon @tomasr8 @Fidget-Spinner @savannahostrowski
|
||||
|
|
@ -308,8 +318,8 @@ Tools/peg_generator/ @pablogsal @lysnikolaou
|
|||
|
||||
# Runtime state/lifecycle
|
||||
**/*gil* @ericsnowcurrently
|
||||
**/*pylifecycle* @ericsnowcurrently @ZeroIntensity
|
||||
**/*pystate* @ericsnowcurrently @ZeroIntensity
|
||||
**/*pylifecycle* @ericsnowcurrently @ZeroIntensity @FFY00
|
||||
**/*pystate* @ericsnowcurrently @ZeroIntensity @FFY00
|
||||
Include/internal/pycore_*_init.h @ericsnowcurrently
|
||||
Include/internal/pycore_*_state.h @ericsnowcurrently
|
||||
Include/internal/pycore_atexit.h @ericsnowcurrently
|
||||
|
|
@ -417,18 +427,19 @@ Lib/dataclasses.py @ericvsmith
|
|||
Lib/test/test_dataclasses/ @ericvsmith
|
||||
|
||||
# Dates and times
|
||||
Doc/**/*time.rst @pganssle @abalkin
|
||||
Doc/library/zoneinfo.rst @pganssle
|
||||
Include/datetime.h @pganssle @abalkin
|
||||
Include/internal/pycore_time.h @pganssle @abalkin
|
||||
Lib/test/test_zoneinfo/ @pganssle
|
||||
Lib/zoneinfo/ @pganssle
|
||||
Lib/*time.py @pganssle @abalkin
|
||||
Lib/test/datetimetester.py @pganssle @abalkin
|
||||
Lib/test/test_*time.py @pganssle @abalkin
|
||||
Modules/*zoneinfo* @pganssle
|
||||
Modules/*time* @pganssle @abalkin
|
||||
Python/pytime.c @pganssle @abalkin
|
||||
Doc/**/*time.rst @pganssle @StanFromIreland
|
||||
Doc/library/datetime-* @pganssle @StanFromIreland
|
||||
Doc/library/zoneinfo.rst @pganssle @StanFromIreland
|
||||
Include/datetime.h @pganssle @StanFromIreland
|
||||
Include/internal/pycore_time.h @pganssle @StanFromIreland
|
||||
Lib/test/test_zoneinfo/ @pganssle @StanFromIreland
|
||||
Lib/zoneinfo/ @pganssle @StanFromIreland
|
||||
Lib/*time.py @pganssle @StanFromIreland
|
||||
Lib/test/datetimetester.py @pganssle @StanFromIreland
|
||||
Lib/test/test_*time.py @pganssle @StanFromIreland
|
||||
Modules/*zoneinfo* @pganssle @StanFromIreland
|
||||
Modules/*time* @pganssle @StanFromIreland
|
||||
Python/pytime.c @pganssle @StanFromIreland
|
||||
|
||||
# Dbm
|
||||
Doc/library/dbm.rst @corona10 @erlend-aasland @serhiy-storchaka
|
||||
|
|
@ -467,8 +478,9 @@ Lib/test/test_functools.py @rhettinger
|
|||
Modules/_functoolsmodule.c @rhettinger
|
||||
|
||||
# Garbage collector
|
||||
Modules/gcmodule.c @pablogsal
|
||||
Doc/library/gc.rst @pablogsal
|
||||
Modules/gcmodule.c @pablogsal
|
||||
Doc/library/gc.rst @pablogsal
|
||||
InternalDocs/garbage_collector.md @pablogsal
|
||||
|
||||
# Gettext
|
||||
Doc/library/gettext.rst @tomasr8
|
||||
|
|
@ -495,13 +507,13 @@ Lib/idlelib/ @terryjreedy
|
|||
Lib/turtledemo/ @terryjreedy
|
||||
|
||||
# importlib.metadata
|
||||
Doc/library/importlib.metadata.rst @jaraco @warsaw
|
||||
Lib/importlib/metadata/ @jaraco @warsaw
|
||||
Lib/test/test_importlib/metadata/ @jaraco @warsaw
|
||||
Doc/library/importlib.metadata.rst @jaraco @warsaw @FFY00
|
||||
Lib/importlib/metadata/ @jaraco @warsaw @FFY00
|
||||
Lib/test/test_importlib/metadata/ @jaraco @warsaw @FFY00
|
||||
|
||||
# importlib.resources
|
||||
Doc/library/importlib.resources.abc.rst @jaraco @warsaw
|
||||
Doc/library/importlib.resources.rst @jaraco @warsaw
|
||||
Doc/library/importlib.resources.abc.rst @jaraco @warsaw @FFY00
|
||||
Doc/library/importlib.resources.rst @jaraco @warsaw @FFY00
|
||||
Lib/importlib/resources/ @jaraco @warsaw @FFY00
|
||||
Lib/test/test_importlib/resources/ @jaraco @warsaw @FFY00
|
||||
|
||||
|
|
|
|||
3
.github/ISSUE_TEMPLATE/documentation.yml
vendored
3
.github/ISSUE_TEMPLATE/documentation.yml
vendored
|
|
@ -8,8 +8,9 @@ body:
|
|||
> [!NOTE]
|
||||
> Trivial changes (for example typos) don’t require an issue before opening a PR.
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: "Documentation"
|
||||
description: "A clear and concise description of the issue."
|
||||
description: "A clear and concise description of the issue. Include a link to the page."
|
||||
validations:
|
||||
required: true
|
||||
|
|
|
|||
5
.github/actionlint.yaml
vendored
5
.github/actionlint.yaml
vendored
|
|
@ -1,8 +1,3 @@
|
|||
self-hosted-runner:
|
||||
# Pending https://github.com/rhysd/actionlint/issues/533
|
||||
# and https://github.com/rhysd/actionlint/issues/571
|
||||
labels: ["windows-11-arm", "macos-15-intel"]
|
||||
|
||||
config-variables: null
|
||||
|
||||
paths:
|
||||
|
|
|
|||
8
.github/dependabot.yml
vendored
8
.github/dependabot.yml
vendored
|
|
@ -3,7 +3,7 @@ updates:
|
|||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
interval: "quarterly"
|
||||
labels:
|
||||
- "skip issue"
|
||||
- "skip news"
|
||||
|
|
@ -12,6 +12,10 @@ updates:
|
|||
update-types:
|
||||
- "version-update:semver-minor"
|
||||
- "version-update:semver-patch"
|
||||
groups:
|
||||
actions:
|
||||
patterns:
|
||||
- "*"
|
||||
cooldown:
|
||||
# https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns
|
||||
# Cooldowns protect against supply chain attacks by avoiding the
|
||||
|
|
@ -20,7 +24,7 @@ updates:
|
|||
- package-ecosystem: "pip"
|
||||
directory: "/Tools/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
interval: "quarterly"
|
||||
labels:
|
||||
- "skip issue"
|
||||
- "skip news"
|
||||
|
|
|
|||
4
.github/workflows/add-issue-header.yml
vendored
4
.github/workflows/add-issue-header.yml
vendored
|
|
@ -12,6 +12,8 @@ on:
|
|||
# Only ever run once
|
||||
- opened
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
add-header:
|
||||
|
|
@ -20,7 +22,7 @@ jobs:
|
|||
issues: write
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/github-script@v8
|
||||
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
with:
|
||||
# language=JavaScript
|
||||
script: |
|
||||
|
|
|
|||
201
.github/workflows/build.yml
vendored
201
.github/workflows/build.yml
vendored
|
|
@ -64,7 +64,7 @@ jobs:
|
|||
run: |
|
||||
apt update && apt install git -yq
|
||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
|
@ -101,18 +101,16 @@ jobs:
|
|||
needs: build-context
|
||||
if: needs.build-context.outputs.run-tests == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v6
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Runner image version
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: Install dependencies
|
||||
run: sudo ./.github/workflows/posix-deps-apt.sh
|
||||
- name: Add ccache to PATH
|
||||
run: echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: Configure CPython
|
||||
run: |
|
||||
# Build Python with the libpython dynamic library
|
||||
|
|
@ -167,13 +165,21 @@ jobs:
|
|||
free-threading:
|
||||
- false
|
||||
- true
|
||||
interpreter:
|
||||
- switch-case
|
||||
exclude:
|
||||
# Skip Win32 on free-threaded builds
|
||||
- { arch: Win32, free-threading: true }
|
||||
include:
|
||||
# msvc::musttail is currently only supported on x64,
|
||||
# and only supported on 3.15+.
|
||||
- { arch: x64, free-threading: false, interpreter: tail-call }
|
||||
- { arch: x64, free-threading: true, interpreter: tail-call }
|
||||
uses: ./.github/workflows/reusable-windows.yml
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
free-threading: ${{ matrix.free-threading }}
|
||||
interpreter: ${{ matrix.interpreter }}
|
||||
|
||||
build-windows-msi:
|
||||
# ${{ '' } is a hack to nest jobs under the same sidebar category.
|
||||
|
|
@ -200,10 +206,10 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# macos-14 is M1, macos-15-intel is Intel.
|
||||
# macos-26 is Apple Silicon, macos-15-intel is Intel.
|
||||
# macos-15-intel only runs tests against the GIL-enabled CPython.
|
||||
os:
|
||||
- macos-14
|
||||
- macos-26
|
||||
- macos-15-intel
|
||||
free-threading:
|
||||
- false
|
||||
|
|
@ -242,14 +248,21 @@ jobs:
|
|||
# BOLT currently crashes during instrumentation on aarch64
|
||||
- os: ubuntu-24.04-arm
|
||||
bolt: true
|
||||
include:
|
||||
# Enable CPU-intensive tests on ARM (default build only)
|
||||
- os: ubuntu-24.04-arm
|
||||
bolt: false
|
||||
free-threading: false
|
||||
test-opts: '-u cpu'
|
||||
uses: ./.github/workflows/reusable-ubuntu.yml
|
||||
with:
|
||||
bolt-optimizations: ${{ matrix.bolt }}
|
||||
free-threading: ${{ matrix.free-threading }}
|
||||
os: ${{ matrix.os }}
|
||||
test-opts: ${{ matrix.test-opts || '' }}
|
||||
|
||||
build-ubuntu-ssltests-openssl:
|
||||
name: 'Ubuntu SSL tests with OpenSSL'
|
||||
build-ubuntu-ssltests:
|
||||
name: 'Ubuntu SSL tests'
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
needs: build-context
|
||||
|
|
@ -258,18 +271,27 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-24.04]
|
||||
# Keep 1.1.1w in our list despite it being upstream EOL and otherwise
|
||||
# unsupported as it most resembles other 1.1.1-work-a-like ssl APIs
|
||||
# supported by important vendors such as AWS-LC.
|
||||
openssl_ver: [1.1.1w, 3.0.18, 3.3.5, 3.4.3, 3.5.4, 3.6.0]
|
||||
# See Tools/ssl/make_ssl_data.py for notes on adding a new version
|
||||
ssllib:
|
||||
# See Tools/ssl/make_ssl_data.py for notes on adding a new version
|
||||
## OpenSSL
|
||||
# Keep 1.1.1w in our list despite it being upstream EOL and otherwise
|
||||
# unsupported as it most resembles other 1.1.1-work-a-like ssl APIs
|
||||
# supported by important vendors such as AWS-LC.
|
||||
- { name: openssl, version: 1.1.1w }
|
||||
- { name: openssl, version: 3.0.19 }
|
||||
- { name: openssl, version: 3.3.6 }
|
||||
- { name: openssl, version: 3.4.4 }
|
||||
- { name: openssl, version: 3.5.5 }
|
||||
- { name: openssl, version: 3.6.1 }
|
||||
## AWS-LC
|
||||
- { name: aws-lc, version: 1.68.0 }
|
||||
env:
|
||||
OPENSSL_VER: ${{ matrix.openssl_ver }}
|
||||
SSLLIB_VER: ${{ matrix.ssllib.version }}
|
||||
MULTISSL_DIR: ${{ github.workspace }}/multissl
|
||||
OPENSSL_DIR: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}
|
||||
LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}/lib
|
||||
SSLLIB_DIR: ${{ github.workspace }}/multissl/${{ matrix.ssllib.name }}/${{ matrix.ssllib.version }}
|
||||
LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/${{ matrix.ssllib.name }}/${{ matrix.ssllib.version }}/lib
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Runner image version
|
||||
|
|
@ -278,95 +300,37 @@ jobs:
|
|||
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
|
||||
- name: Install dependencies
|
||||
run: sudo ./.github/workflows/posix-deps-apt.sh
|
||||
- name: Configure OpenSSL env vars
|
||||
run: |
|
||||
echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV"
|
||||
echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV"
|
||||
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
|
||||
- name: 'Restore OpenSSL build'
|
||||
id: cache-openssl
|
||||
uses: actions/cache@v5
|
||||
- name: 'Restore SSL library build'
|
||||
id: cache-ssl-lib
|
||||
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
|
||||
key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
|
||||
- name: Install OpenSSL
|
||||
if: steps.cache-openssl.outputs.cache-hit != 'true'
|
||||
run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux
|
||||
- name: Add ccache to PATH
|
||||
run: |
|
||||
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: Configure CPython
|
||||
run: ./configure CFLAGS="-fdiagnostics-format=json" --config-cache --enable-slower-safety --with-pydebug --with-openssl="$OPENSSL_DIR"
|
||||
- name: Build CPython
|
||||
run: make -j4
|
||||
- name: Display build info
|
||||
run: make pythoninfo
|
||||
- name: SSL tests
|
||||
run: ./python Lib/test/ssltests.py
|
||||
|
||||
build-ubuntu-ssltests-awslc:
|
||||
name: 'Ubuntu SSL tests with AWS-LC'
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
needs: build-context
|
||||
if: needs.build-context.outputs.run-ubuntu == 'true'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-24.04]
|
||||
awslc_ver: [1.55.0]
|
||||
env:
|
||||
AWSLC_VER: ${{ matrix.awslc_ver}}
|
||||
MULTISSL_DIR: ${{ github.workspace }}/multissl
|
||||
OPENSSL_DIR: ${{ github.workspace }}/multissl/aws-lc/${{ matrix.awslc_ver }}
|
||||
LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/aws-lc/${{ matrix.awslc_ver }}/lib
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Runner image version
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: Register gcc problem matcher
|
||||
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
|
||||
- name: Install dependencies
|
||||
run: sudo ./.github/workflows/posix-deps-apt.sh
|
||||
- name: Configure SSL lib env vars
|
||||
run: |
|
||||
echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV"
|
||||
echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/aws-lc/${AWSLC_VER}" >> "$GITHUB_ENV"
|
||||
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/aws-lc/${AWSLC_VER}/lib" >> "$GITHUB_ENV"
|
||||
- name: 'Restore AWS-LC build'
|
||||
id: cache-aws-lc
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ./multissl/aws-lc/${{ matrix.awslc_ver }}
|
||||
key: ${{ matrix.os }}-multissl-aws-lc-${{ matrix.awslc_ver }}
|
||||
- name: Install AWS-LC
|
||||
if: steps.cache-aws-lc.outputs.cache-hit != 'true'
|
||||
path: ./multissl/${{ matrix.ssllib.name }}/${{ matrix.ssllib.version }}
|
||||
key: ${{ matrix.os }}-multissl-${{ matrix.ssllib.name }}-${{ matrix.ssllib.version }}
|
||||
- name: Install SSL Library
|
||||
if: steps.cache-ssl-lib.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
python3 Tools/ssl/multissltests.py \
|
||||
--steps=library \
|
||||
--base-directory "$MULTISSL_DIR" \
|
||||
--awslc ${{ matrix.awslc_ver }} \
|
||||
'--${{ matrix.ssllib.name }}' '${{ matrix.ssllib.version }}' \
|
||||
--system Linux
|
||||
- name: Add ccache to PATH
|
||||
run: |
|
||||
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: Configure CPython
|
||||
run: |
|
||||
./configure CFLAGS="-fdiagnostics-format=json" \
|
||||
--config-cache \
|
||||
--enable-slower-safety \
|
||||
--with-pydebug \
|
||||
--with-openssl="$OPENSSL_DIR" \
|
||||
--with-openssl="$SSLLIB_DIR" \
|
||||
--with-builtin-hashlib-hashes=blake2 \
|
||||
--with-ssl-default-suites=openssl
|
||||
- name: Build CPython
|
||||
run: make -j
|
||||
run: make -j4
|
||||
- name: Display build info
|
||||
run: make pythoninfo
|
||||
- name: Verify python is linked to AWS-LC
|
||||
run: ./python -c 'import ssl; print(ssl.OPENSSL_VERSION)' | grep AWS-LC
|
||||
- name: Verify python is linked to the right lib
|
||||
run: |
|
||||
./python -c 'import ssl; print(ssl.OPENSSL_VERSION)' \
|
||||
| grep -iE '${{ matrix.ssllib.name }}.*${{ matrix.ssllib.version }}'
|
||||
- name: SSL tests
|
||||
run: ./python Lib/test/ssltests.py
|
||||
|
||||
|
|
@ -380,17 +344,17 @@ jobs:
|
|||
matrix:
|
||||
include:
|
||||
- arch: aarch64
|
||||
runs-on: macos-14
|
||||
runs-on: macos-26
|
||||
- arch: x86_64
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Build and test
|
||||
run: ./Android/android.py ci --fast-ci ${{ matrix.arch }}-linux-android
|
||||
run: python3 Platforms/Android ci --fast-ci ${{ matrix.arch }}-linux-android
|
||||
|
||||
build-ios:
|
||||
name: iOS
|
||||
|
|
@ -399,7 +363,7 @@ jobs:
|
|||
timeout-minutes: 60
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
@ -413,7 +377,13 @@ jobs:
|
|||
sudo xcode-select --switch /Applications/Xcode_15.4.app
|
||||
|
||||
- name: Build and test
|
||||
run: python3 Apple ci iOS --fast-ci --simulator 'iPhone SE (3rd generation),OS=17.5'
|
||||
run: python3 Platforms/Apple ci iOS --fast-ci --simulator 'iPhone SE (3rd generation),OS=17.5'
|
||||
|
||||
build-emscripten:
|
||||
name: 'Emscripten'
|
||||
needs: build-context
|
||||
if: needs.build-context.outputs.run-emscripten == 'true'
|
||||
uses: ./.github/workflows/reusable-emscripten.yml
|
||||
|
||||
build-wasi:
|
||||
name: 'WASI'
|
||||
|
|
@ -428,10 +398,10 @@ jobs:
|
|||
needs: build-context
|
||||
if: needs.build-context.outputs.run-ubuntu == 'true'
|
||||
env:
|
||||
OPENSSL_VER: 3.0.18
|
||||
OPENSSL_VER: 3.5.5
|
||||
PYTHONSTRICTEXTENSIONBUILD: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Register gcc problem matcher
|
||||
|
|
@ -445,16 +415,13 @@ jobs:
|
|||
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
|
||||
- name: 'Restore OpenSSL build'
|
||||
id: cache-openssl
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
|
||||
key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
|
||||
- name: Install OpenSSL
|
||||
if: steps.cache-openssl.outputs.cache-hit != 'true'
|
||||
run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux
|
||||
- name: Add ccache to PATH
|
||||
run: |
|
||||
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: Setup directory envs for out-of-tree builds
|
||||
run: |
|
||||
echo "CPYTHON_RO_SRCDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-ro-srcdir)" >> "$GITHUB_ENV"
|
||||
|
|
@ -495,7 +462,7 @@ jobs:
|
|||
./python -m venv "$VENV_LOC" && "$VENV_PYTHON" -m pip install -r "${GITHUB_WORKSPACE}/Tools/requirements-hypothesis.txt"
|
||||
- name: 'Restore Hypothesis database'
|
||||
id: cache-hypothesis-database
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ${{ env.CPYTHON_BUILDDIR }}/.hypothesis/
|
||||
key: hypothesis-database-${{ github.head_ref || github.run_id }}
|
||||
|
|
@ -522,7 +489,7 @@ jobs:
|
|||
-x test_subprocess \
|
||||
-x test_signal \
|
||||
-x test_sysconfig
|
||||
- uses: actions/upload-artifact@v6
|
||||
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
if: always()
|
||||
with:
|
||||
name: hypothesis-example-db
|
||||
|
|
@ -539,11 +506,11 @@ jobs:
|
|||
matrix:
|
||||
os: [ubuntu-24.04]
|
||||
env:
|
||||
OPENSSL_VER: 3.0.18
|
||||
OPENSSL_VER: 3.5.5
|
||||
PYTHONSTRICTEXTENSIONBUILD: 1
|
||||
ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Runner image version
|
||||
|
|
@ -553,7 +520,7 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: sudo ./.github/workflows/posix-deps-apt.sh
|
||||
- name: Set up GCC-10 for ASAN
|
||||
uses: egor-tensin/setup-gcc@v2
|
||||
uses: egor-tensin/setup-gcc@a2861a8b8538f49cf2850980acccf6b05a1b2ae4 # v2.0
|
||||
with:
|
||||
version: 10
|
||||
- name: Configure OpenSSL env vars
|
||||
|
|
@ -563,18 +530,15 @@ jobs:
|
|||
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
|
||||
- name: 'Restore OpenSSL build'
|
||||
id: cache-openssl
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
|
||||
key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
|
||||
- name: Install OpenSSL
|
||||
if: steps.cache-openssl.outputs.cache-hit != 'true'
|
||||
run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux
|
||||
- name: Add ccache to PATH
|
||||
run: |
|
||||
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: Configure CPython
|
||||
run: ./configure --config-cache --with-address-sanitizer --without-pymalloc
|
||||
run: ./configure --config-cache --with-address-sanitizer --without-pymalloc --with-openssl="$OPENSSL_DIR"
|
||||
- name: Build CPython
|
||||
run: make -j4
|
||||
- name: Display build info
|
||||
|
|
@ -613,7 +577,7 @@ jobs:
|
|||
needs: build-context
|
||||
if: needs.build-context.outputs.run-ubuntu == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Runner image version
|
||||
|
|
@ -649,6 +613,7 @@ jobs:
|
|||
needs.build-context.outputs.run-ci-fuzz == 'true'
|
||||
|| needs.build-context.outputs.run-ci-fuzz-stdlib == 'true'
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
@ -698,9 +663,9 @@ jobs:
|
|||
- build-windows-msi
|
||||
- build-macos
|
||||
- build-ubuntu
|
||||
- build-ubuntu-ssltests-awslc
|
||||
- build-ubuntu-ssltests-openssl
|
||||
- build-ubuntu-ssltests
|
||||
- build-ios
|
||||
- build-emscripten
|
||||
- build-wasi
|
||||
- test-hypothesis
|
||||
- build-asan
|
||||
|
|
@ -715,9 +680,9 @@ jobs:
|
|||
with:
|
||||
allowed-failures: >-
|
||||
build-android,
|
||||
build-emscripten,
|
||||
build-windows-msi,
|
||||
build-ubuntu-ssltests-awslc,
|
||||
build-ubuntu-ssltests-openssl,
|
||||
build-ubuntu-ssltests,
|
||||
test-hypothesis,
|
||||
cifuzz,
|
||||
allowed-skips: >-
|
||||
|
|
@ -748,8 +713,7 @@ jobs:
|
|||
!fromJSON(needs.build-context.outputs.run-ubuntu)
|
||||
&& '
|
||||
build-ubuntu,
|
||||
build-ubuntu-ssltests-awslc,
|
||||
build-ubuntu-ssltests-openssl,
|
||||
build-ubuntu-ssltests,
|
||||
test-hypothesis,
|
||||
build-asan,
|
||||
build-san,
|
||||
|
|
@ -759,5 +723,6 @@ jobs:
|
|||
}}
|
||||
${{ !fromJSON(needs.build-context.outputs.run-android) && 'build-android,' || '' }}
|
||||
${{ !fromJSON(needs.build-context.outputs.run-ios) && 'build-ios,' || '' }}
|
||||
${{ !fromJSON(needs.build-context.outputs.run-emscripten) && 'build-emscripten,' || '' }}
|
||||
${{ !fromJSON(needs.build-context.outputs.run-wasi) && 'build-wasi,' || '' }}
|
||||
jobs: ${{ toJSON(needs) }}
|
||||
|
|
|
|||
2
.github/workflows/documentation-links.yml
vendored
2
.github/workflows/documentation-links.yml
vendored
|
|
@ -22,7 +22,7 @@ jobs:
|
|||
timeout-minutes: 5
|
||||
|
||||
steps:
|
||||
- uses: readthedocs/actions/preview@v1
|
||||
- uses: readthedocs/actions/preview@b8bba1484329bda1a3abe986df7ebc80a8950333 # v1.5
|
||||
with:
|
||||
project-slug: "cpython-previews"
|
||||
single-version: "true"
|
||||
|
|
|
|||
219
.github/workflows/jit.yml
vendored
219
.github/workflows/jit.yml
vendored
|
|
@ -1,7 +1,7 @@
|
|||
name: JIT
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
paths: &paths
|
||||
- '**jit**'
|
||||
- 'Python/bytecodes.c'
|
||||
- 'Python/optimizer*.c'
|
||||
|
|
@ -12,16 +12,7 @@ on:
|
|||
- '!**/*.md'
|
||||
- '!**/*.ini'
|
||||
push:
|
||||
paths:
|
||||
- '**jit**'
|
||||
- 'Python/bytecodes.c'
|
||||
- 'Python/optimizer*.c'
|
||||
- 'Python/executor_cases.c.h'
|
||||
- 'Python/optimizer_cases.c.h'
|
||||
- '**_testinternalcapi**'
|
||||
- '!Python/perf_jit_trampoline.c'
|
||||
- '!**/*.md'
|
||||
- '!**/*.ini'
|
||||
paths: *paths
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
|
|
@ -33,14 +24,15 @@ concurrency:
|
|||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
LLVM_VERSION: 21
|
||||
|
||||
jobs:
|
||||
interpreter:
|
||||
name: Interpreter (Debug)
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Build tier two interpreter
|
||||
|
|
@ -50,11 +42,12 @@ jobs:
|
|||
- name: Test tier two interpreter
|
||||
run: |
|
||||
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
|
||||
jit:
|
||||
|
||||
windows:
|
||||
name: ${{ matrix.target }} (${{ matrix.debug && 'Debug' || 'Release' }})
|
||||
needs: interpreter
|
||||
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -62,57 +55,66 @@ jobs:
|
|||
- i686-pc-windows-msvc/msvc
|
||||
- x86_64-pc-windows-msvc/msvc
|
||||
- aarch64-pc-windows-msvc/msvc
|
||||
- x86_64-apple-darwin/clang
|
||||
- aarch64-apple-darwin/clang
|
||||
- x86_64-unknown-linux-gnu/gcc
|
||||
- aarch64-unknown-linux-gnu/gcc
|
||||
debug:
|
||||
- true
|
||||
- false
|
||||
llvm:
|
||||
- 21
|
||||
include:
|
||||
- target: i686-pc-windows-msvc/msvc
|
||||
architecture: Win32
|
||||
runner: windows-2022
|
||||
runner: windows-2025-vs2026
|
||||
- target: x86_64-pc-windows-msvc/msvc
|
||||
architecture: x64
|
||||
runner: windows-2022
|
||||
runner: windows-2025-vs2026
|
||||
- target: aarch64-pc-windows-msvc/msvc
|
||||
architecture: ARM64
|
||||
runner: windows-11-arm
|
||||
- target: x86_64-apple-darwin/clang
|
||||
architecture: x86_64
|
||||
runner: macos-15-intel
|
||||
- target: aarch64-apple-darwin/clang
|
||||
architecture: aarch64
|
||||
runner: macos-14
|
||||
- target: x86_64-unknown-linux-gnu/gcc
|
||||
architecture: x86_64
|
||||
runner: ubuntu-24.04
|
||||
- target: aarch64-unknown-linux-gnu/gcc
|
||||
architecture: aarch64
|
||||
runner: ubuntu-24.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v6
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
# PCbuild downloads LLVM automatically:
|
||||
- name: Windows
|
||||
if: runner.os == 'Windows'
|
||||
- name: Build
|
||||
run: |
|
||||
./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }}
|
||||
- name: Test
|
||||
run: |
|
||||
./PCbuild/rt.bat ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
|
||||
|
||||
- name: macOS
|
||||
if: runner.os == 'macOS'
|
||||
macos:
|
||||
name: ${{ matrix.target }} (${{ matrix.debug && 'Debug' || 'Release' }})
|
||||
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target:
|
||||
- x86_64-apple-darwin/clang
|
||||
- aarch64-apple-darwin/clang
|
||||
debug:
|
||||
- true
|
||||
- false
|
||||
include:
|
||||
- target: x86_64-apple-darwin/clang
|
||||
runner: macos-15-intel
|
||||
- target: aarch64-apple-darwin/clang
|
||||
runner: macos-15
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Install LLVM
|
||||
run: |
|
||||
brew update
|
||||
brew install llvm@${{ matrix.llvm }}
|
||||
brew install llvm@${{ env.LLVM_VERSION }}
|
||||
- name: Build
|
||||
run: |
|
||||
export SDKROOT="$(xcrun --show-sdk-path)"
|
||||
# Set MACOSX_DEPLOYMENT_TARGET and -Werror=unguarded-availability to
|
||||
# make sure we don't break downstream distributors (like uv):
|
||||
|
|
@ -120,92 +122,83 @@ jobs:
|
|||
export MACOSX_DEPLOYMENT_TARGET=10.15
|
||||
./configure --enable-experimental-jit --enable-universalsdk --with-universal-archs=universal2 ${{ matrix.debug && '--with-pydebug' || '' }}
|
||||
make all --jobs 4
|
||||
- name: Test
|
||||
run: |
|
||||
./python.exe -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
|
||||
|
||||
- name: Linux
|
||||
if: runner.os == 'Linux'
|
||||
linux:
|
||||
name: ${{ matrix.target }} (${{ matrix.debug && 'Debug' || 'Release' }})
|
||||
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target:
|
||||
- x86_64-unknown-linux-gnu/gcc
|
||||
- aarch64-unknown-linux-gnu/gcc
|
||||
debug:
|
||||
- true
|
||||
- false
|
||||
include:
|
||||
- target: x86_64-unknown-linux-gnu/gcc
|
||||
runner: ubuntu-24.04
|
||||
- target: aarch64-unknown-linux-gnu/gcc
|
||||
runner: ubuntu-24.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Build
|
||||
run: |
|
||||
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
|
||||
export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH"
|
||||
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ env.LLVM_VERSION }}
|
||||
export PATH="$(llvm-config-${{ env.LLVM_VERSION }} --bindir):$PATH"
|
||||
./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '' }}
|
||||
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
|
||||
timeout-minutes: 90
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
llvm:
|
||||
- 21
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v6
|
||||
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
|
||||
- name: Test
|
||||
run: |
|
||||
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
|
||||
continue-on-error: true
|
||||
|
||||
no-opt-jit:
|
||||
name: JIT without optimizations (Debug)
|
||||
needs: interpreter
|
||||
linux-extras:
|
||||
name: ${{ matrix.name }}
|
||||
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
llvm:
|
||||
- 21
|
||||
include:
|
||||
- name: Free-Threaded (Debug)
|
||||
configure_flags: --enable-experimental-jit --with-pydebug --disable-gil
|
||||
continue_on_error: true
|
||||
- name: JIT without optimizations (Debug)
|
||||
configure_flags: --enable-experimental-jit --with-pydebug
|
||||
test_env: "PYTHON_UOPS_OPTIMIZE=0"
|
||||
- name: JIT with tail calling interpreter
|
||||
configure_flags: --enable-experimental-jit --with-tail-call-interp --with-pydebug
|
||||
use_clang: true
|
||||
run_tests: false
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v6
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Build with JIT
|
||||
- name: Build
|
||||
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
|
||||
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ env.LLVM_VERSION }}
|
||||
export PATH="$(llvm-config-${{ env.LLVM_VERSION }} --bindir):$PATH"
|
||||
if [ "${{ matrix.use_clang }}" = "true" ]; then
|
||||
export CC=clang-${{ env.LLVM_VERSION }}
|
||||
fi
|
||||
./configure ${{ matrix.configure_flags }}
|
||||
make all --jobs 4
|
||||
- name: Run tests without optimizations
|
||||
- name: Test
|
||||
if: matrix.run_tests != false
|
||||
run: |
|
||||
PYTHON_UOPS_OPTIMIZE=0 ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
|
||||
|
||||
tail-call-jit:
|
||||
name: JIT with tail calling interpreter
|
||||
needs: interpreter
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 90
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
llvm:
|
||||
- 21
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Build with JIT and tailcall
|
||||
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-${{ matrix.llvm }} ./configure --enable-experimental-jit --with-tail-call-interp --with-pydebug
|
||||
make all --jobs 4
|
||||
${{ matrix.test_env }} ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
|
||||
continue-on-error: ${{ matrix.continue_on_error }}
|
||||
|
|
|
|||
4
.github/workflows/lint.yml
vendored
4
.github/workflows/lint.yml
vendored
|
|
@ -19,7 +19,7 @@ jobs:
|
|||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: j178/prek-action@v1
|
||||
- uses: j178/prek-action@0bb87d7f00b0c99306c8bcb8b8beba1eb581c037 # v1.1.1
|
||||
|
|
|
|||
5
.github/workflows/mypy.yml
vendored
5
.github/workflows/mypy.yml
vendored
|
|
@ -19,6 +19,7 @@ on:
|
|||
- "Tools/build/consts_getter.py"
|
||||
- "Tools/build/deepfreeze.py"
|
||||
- "Tools/build/generate-build-details.py"
|
||||
- "Tools/build/generate_levenshtein_examples.py"
|
||||
- "Tools/build/generate_sbom.py"
|
||||
- "Tools/build/generate_stdlib_module_names.py"
|
||||
- "Tools/build/mypy.ini"
|
||||
|
|
@ -65,10 +66,10 @@ jobs:
|
|||
"Tools/peg_generator",
|
||||
]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v6
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
cache: pip
|
||||
|
|
|
|||
10
.github/workflows/new-bugs-announce-notifier.yml
vendored
10
.github/workflows/new-bugs-announce-notifier.yml
vendored
|
|
@ -6,19 +6,21 @@ on:
|
|||
- opened
|
||||
|
||||
permissions:
|
||||
issues: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
notify-new-bugs-announce:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: read
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/setup-node@v6
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: 20
|
||||
- run: npm install mailgun.js form-data
|
||||
- name: Send notification
|
||||
uses: actions/github-script@v8
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
env:
|
||||
MAILGUN_API_KEY: ${{ secrets.MAILGUN_PYTHON_ORG_MAILGUN_KEY }}
|
||||
with:
|
||||
|
|
@ -44,7 +46,7 @@ jobs:
|
|||
// We need to truncate the body size, because the max size for
|
||||
// the whole payload is 16kb. We want to be safe and assume that
|
||||
// body can take up to ~8kb of space.
|
||||
body : issue.data.body.substring(0, 8000)
|
||||
body : (issue.data.body || "").substring(0, 8000)
|
||||
};
|
||||
|
||||
const data = {
|
||||
|
|
|
|||
5
.github/workflows/posix-deps-apt.sh
vendored
5
.github/workflows/posix-deps-apt.sh
vendored
|
|
@ -1,10 +1,9 @@
|
|||
#!/bin/sh
|
||||
apt-get update
|
||||
|
||||
apt-get -yq install \
|
||||
apt-get -yq --no-install-recommends install \
|
||||
build-essential \
|
||||
pkg-config \
|
||||
ccache \
|
||||
cmake \
|
||||
gdb \
|
||||
lcov \
|
||||
|
|
@ -32,4 +31,4 @@ apt-get -yq install \
|
|||
# https://deb.sury.org/
|
||||
sudo add-apt-repository ppa:ondrej/php
|
||||
apt-get update
|
||||
apt-get -yq install libmpdec-dev
|
||||
apt-get -yq --no-install-recommends install libmpdec-dev
|
||||
|
|
|
|||
2
.github/workflows/regen-abidump.sh
vendored
2
.github/workflows/regen-abidump.sh
vendored
|
|
@ -2,7 +2,7 @@ set -ex
|
|||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
./.github/workflows/posix-deps-apt.sh
|
||||
apt-get install -yq abigail-tools python3
|
||||
apt-get install -yq --no-install-recommends abigail-tools python3
|
||||
export CFLAGS="-g3 -O0"
|
||||
./configure --enable-shared && make
|
||||
make regen-abidump
|
||||
|
|
|
|||
11
.github/workflows/require-pr-label.yml
vendored
11
.github/workflows/require-pr-label.yml
vendored
|
|
@ -4,6 +4,9 @@ on:
|
|||
pull_request:
|
||||
types: [opened, reopened, labeled, unlabeled, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
label-dnm:
|
||||
name: DO-NOT-MERGE
|
||||
|
|
@ -15,7 +18,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Check there's no DO-NOT-MERGE
|
||||
uses: mheap/github-action-required-labels@v5
|
||||
uses: mheap/github-action-required-labels@0ac283b4e65c1fb28ce6079dea5546ceca98ccbe # v5.5.2
|
||||
with:
|
||||
mode: exactly
|
||||
count: 0
|
||||
|
|
@ -33,7 +36,7 @@ jobs:
|
|||
steps:
|
||||
# Check that the PR is not awaiting changes from the author due to previous review.
|
||||
- name: Check there's no required changes
|
||||
uses: mheap/github-action-required-labels@v5
|
||||
uses: mheap/github-action-required-labels@0ac283b4e65c1fb28ce6079dea5546ceca98ccbe # v5.5.2
|
||||
with:
|
||||
mode: exactly
|
||||
count: 0
|
||||
|
|
@ -42,7 +45,7 @@ jobs:
|
|||
awaiting change review
|
||||
- id: is-feature
|
||||
name: Check whether this PR is a feature (contains a "type-feature" label)
|
||||
uses: mheap/github-action-required-labels@v5
|
||||
uses: mheap/github-action-required-labels@0ac283b4e65c1fb28ce6079dea5546ceca98ccbe # v5.5.2
|
||||
with:
|
||||
mode: exactly
|
||||
count: 1
|
||||
|
|
@ -53,7 +56,7 @@ jobs:
|
|||
- id: awaiting-merge
|
||||
if: steps.is-feature.outputs.status == 'success'
|
||||
name: Check for complete review
|
||||
uses: mheap/github-action-required-labels@v5
|
||||
uses: mheap/github-action-required-labels@0ac283b4e65c1fb28ce6079dea5546ceca98ccbe # v5.5.2
|
||||
with:
|
||||
mode: exactly
|
||||
count: 1
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v5
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Check for undocumented C APIs
|
||||
|
|
|
|||
67
.github/workflows/reusable-check-html-ids.yml
vendored
Normal file
67
.github/workflows/reusable-check-html-ids.yml
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
name: Reusable check HTML IDs
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
||||
jobs:
|
||||
check-html-ids:
|
||||
name: 'Check for removed HTML IDs'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: 'Check out PR head'
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: 'Find merge base'
|
||||
id: merge-base
|
||||
run: |
|
||||
BASE="${{ github.event.pull_request.base.sha }}"
|
||||
HEAD="${{ github.event.pull_request.head.sha }}"
|
||||
git fetch --depth=$((${{ github.event.pull_request.commits }} + 10)) --no-tags origin "$BASE" "$HEAD"
|
||||
|
||||
if ! MERGE_BASE=$(git merge-base "$BASE" "$HEAD" 2>/dev/null); then
|
||||
git fetch --deepen=1 --no-tags origin "$BASE" "$HEAD"
|
||||
|
||||
OLDEST=$(git rev-list --reflog --max-parents=0 --reverse "${BASE}^" "${HEAD}^" | head -1)
|
||||
TIMESTAMP=$(git show --format=%at --no-patch "$OLDEST")
|
||||
|
||||
git fetch --shallow-since="$TIMESTAMP" --no-tags origin "$BASE" "$HEAD"
|
||||
|
||||
MERGE_BASE=$(git merge-base "$BASE" "$HEAD")
|
||||
fi
|
||||
echo "sha=$MERGE_BASE" >> "$GITHUB_OUTPUT"
|
||||
- name: 'Create worktree at merge base'
|
||||
env:
|
||||
MERGE_BASE: ${{ steps.merge-base.outputs.sha }}
|
||||
run: git worktree add /tmp/merge-base "$MERGE_BASE" --detach
|
||||
- name: 'Set up Python'
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3'
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'Doc/requirements.txt'
|
||||
- name: 'Install build dependencies'
|
||||
run: make -C /tmp/merge-base/Doc/ venv
|
||||
- name: 'Build HTML documentation'
|
||||
run: make -C /tmp/merge-base/Doc/ SPHINXOPTS="--quiet" html
|
||||
- name: 'Collect HTML IDs'
|
||||
run: python Doc/tools/check-html-ids.py collect /tmp/merge-base/Doc/build/html -o /tmp/html-ids-base.json.gz
|
||||
- name: 'Download PR head HTML IDs'
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: html-ids-head.json.gz
|
||||
path: /tmp
|
||||
- name: 'Check for removed HTML IDs'
|
||||
run: |
|
||||
# shellcheck disable=SC2046
|
||||
python Doc/tools/check-html-ids.py -v check \
|
||||
/tmp/html-ids-base.json.gz /tmp/html-ids-head.json.gz \
|
||||
$([ -f Doc/tools/removed-ids.txt ] && echo "--exclude-file Doc/tools/removed-ids.txt")
|
||||
11
.github/workflows/reusable-cifuzz.yml
vendored
11
.github/workflows/reusable-cifuzz.yml
vendored
|
|
@ -13,6 +13,9 @@ on:
|
|||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
cifuzz:
|
||||
name: ${{ inputs.oss-fuzz-project-name }} (${{ inputs.sanitizer }})
|
||||
|
|
@ -21,12 +24,12 @@ jobs:
|
|||
steps:
|
||||
- name: Build fuzzers (${{ inputs.sanitizer }})
|
||||
id: build
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@ed23f8af80ff82b25ca67cd9b101e690b8897b3f # master
|
||||
with:
|
||||
oss-fuzz-project-name: ${{ inputs.oss-fuzz-project-name }}
|
||||
sanitizer: ${{ inputs.sanitizer }}
|
||||
- name: Run fuzzers (${{ inputs.sanitizer }})
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@ed23f8af80ff82b25ca67cd9b101e690b8897b3f # master
|
||||
with:
|
||||
fuzz-seconds: 600
|
||||
oss-fuzz-project-name: ${{ inputs.oss-fuzz-project-name }}
|
||||
|
|
@ -34,13 +37,13 @@ jobs:
|
|||
sanitizer: ${{ inputs.sanitizer }}
|
||||
- name: Upload crash
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ inputs.sanitizer }}-artifacts
|
||||
path: ./out/artifacts
|
||||
- name: Upload SARIF
|
||||
if: always() && steps.build.outcome == 'success'
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
|
||||
with:
|
||||
sarif_file: cifuzz-sarif/results.sarif
|
||||
checkout_path: cifuzz-sarif
|
||||
|
|
|
|||
11
.github/workflows/reusable-context.yml
vendored
11
.github/workflows/reusable-context.yml
vendored
|
|
@ -41,6 +41,9 @@ on: # yamllint disable-line rule:truthy
|
|||
run-ubuntu:
|
||||
description: Whether to run the Ubuntu tests
|
||||
value: ${{ jobs.compute-changes.outputs.run-ubuntu }} # bool
|
||||
run-emscripten:
|
||||
description: Whether to run the Emscripten tests
|
||||
value: ${{ jobs.compute-changes.outputs.run-emscripten }} # bool
|
||||
run-wasi:
|
||||
description: Whether to run the WASI tests
|
||||
value: ${{ jobs.compute-changes.outputs.run-wasi }} # bool
|
||||
|
|
@ -51,6 +54,9 @@ on: # yamllint disable-line rule:truthy
|
|||
description: Whether to run the Windows tests
|
||||
value: ${{ jobs.compute-changes.outputs.run-windows-tests }} # bool
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
compute-changes:
|
||||
name: Create context from changed files
|
||||
|
|
@ -65,19 +71,20 @@ jobs:
|
|||
run-macos: ${{ steps.changes.outputs.run-macos }}
|
||||
run-tests: ${{ steps.changes.outputs.run-tests }}
|
||||
run-ubuntu: ${{ steps.changes.outputs.run-ubuntu }}
|
||||
run-emscripten: ${{ steps.changes.outputs.run-emscripten }}
|
||||
run-wasi: ${{ steps.changes.outputs.run-wasi }}
|
||||
run-windows-msi: ${{ steps.changes.outputs.run-windows-msi }}
|
||||
run-windows-tests: ${{ steps.changes.outputs.run-windows-tests }}
|
||||
steps:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3"
|
||||
|
||||
- run: >-
|
||||
echo '${{ github.event_name }}'
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: >-
|
||||
|
|
|
|||
30
.github/workflows/reusable-docs.yml
vendored
30
.github/workflows/reusable-docs.yml
vendored
|
|
@ -27,7 +27,7 @@ jobs:
|
|||
refspec_pr: '+${{ github.event.pull_request.head.sha }}:remotes/origin/${{ github.event.pull_request.head.ref }}'
|
||||
steps:
|
||||
- name: 'Check out latest PR branch commit'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: >-
|
||||
|
|
@ -52,7 +52,7 @@ jobs:
|
|||
git fetch origin "${refspec_base}" --shallow-since="${DATE}" \
|
||||
--no-tags --prune --no-recurse-submodules
|
||||
- name: 'Set up Python'
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3'
|
||||
cache: 'pip'
|
||||
|
|
@ -75,6 +75,22 @@ jobs:
|
|||
--fail-if-regression \
|
||||
--fail-if-improved \
|
||||
--fail-if-new-news-nit
|
||||
- name: 'Collect HTML IDs'
|
||||
if: github.event_name == 'pull_request'
|
||||
run: python Doc/tools/check-html-ids.py collect Doc/build/html -o Doc/build/html-ids-head.json.gz
|
||||
- name: 'Upload HTML IDs'
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: html-ids-head
|
||||
path: Doc/build/html-ids-head.json.gz
|
||||
archive: false
|
||||
|
||||
check-html-ids:
|
||||
name: 'Check for removed HTML IDs'
|
||||
needs: build-doc
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: ./.github/workflows/reusable-check-html-ids.yml
|
||||
|
||||
# Run "doctest" on HEAD as new syntax doesn't exist in the latest stable release
|
||||
doctest:
|
||||
|
|
@ -82,17 +98,17 @@ jobs:
|
|||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/cache@v5
|
||||
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ubuntu-doc-${{ hashFiles('Doc/requirements.txt') }}
|
||||
restore-keys: |
|
||||
ubuntu-doc-
|
||||
- name: 'Install Dependencies'
|
||||
run: sudo ./.github/workflows/posix-deps-apt.sh && sudo apt-get install wamerican
|
||||
run: sudo ./.github/workflows/posix-deps-apt.sh && sudo apt-get install --no-install-recommends wamerican
|
||||
- name: 'Configure CPython'
|
||||
run: ./configure --with-pydebug
|
||||
- name: 'Build CPython'
|
||||
|
|
@ -108,11 +124,11 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: 'Set up Python'
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3'
|
||||
cache: 'pip'
|
||||
|
|
|
|||
77
.github/workflows/reusable-emscripten.yml
vendored
Normal file
77
.github/workflows/reusable-emscripten.yml
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
name: Reusable Emscripten
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
||||
jobs:
|
||||
build-emscripten-reusable:
|
||||
name: 'build and test'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 40
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: "Read Emscripten config"
|
||||
id: emscripten-config
|
||||
shell: python
|
||||
run: |
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
|
||||
config = tomllib.loads(Path("Platforms/emscripten/config.toml").read_text())
|
||||
h = hashlib.sha256()
|
||||
h.update(json.dumps(config["dependencies"], sort_keys=True).encode())
|
||||
h.update(Path("Platforms/emscripten/make_libffi.sh").read_bytes())
|
||||
h.update(b'1') # Update to explicitly bust cache
|
||||
emsdk_cache = Path(os.environ["RUNNER_TEMP"]) / "emsdk-cache"
|
||||
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
|
||||
f.write(f"emscripten-version={config['emscripten-version']}\n")
|
||||
f.write(f"node-version={config['node-version']}\n")
|
||||
f.write(f"deps-hash={h.hexdigest()}\n")
|
||||
with open(os.environ["GITHUB_ENV"], "a") as f:
|
||||
f.write(f"EMSDK_CACHE={emsdk_cache}\n")
|
||||
- name: "Install Node.js"
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version: ${{ steps.emscripten-config.outputs.node-version }}
|
||||
- name: "Cache Emscripten SDK"
|
||||
id: emsdk-cache
|
||||
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ${{ env.EMSDK_CACHE }}
|
||||
key: emsdk-${{ steps.emscripten-config.outputs.emscripten-version }}-${{ steps.emscripten-config.outputs.deps-hash }}
|
||||
restore-keys: emsdk-${{ steps.emscripten-config.outputs.emscripten-version }}
|
||||
- name: "Install Python"
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: "Runner image version"
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: "Install Emscripten"
|
||||
run: python3 Platforms/emscripten install-emscripten
|
||||
- name: "Configure build Python"
|
||||
run: python3 Platforms/emscripten configure-build-python -- --config-cache --with-pydebug
|
||||
- name: "Make build Python"
|
||||
run: python3 Platforms/emscripten make-build-python
|
||||
- name: "Make dependencies"
|
||||
run: >-
|
||||
python3 Platforms/emscripten make-dependencies
|
||||
${{ steps.emsdk-cache.outputs.cache-hit == 'true' && '--check-up-to-date' || '' }}
|
||||
- name: "Configure host Python"
|
||||
run: python3 Platforms/emscripten configure-host --host-runner node -- --config-cache
|
||||
- name: "Make host Python"
|
||||
run: python3 Platforms/emscripten make-host
|
||||
- name: "Display build info"
|
||||
run: python3 Platforms/emscripten run --pythoninfo
|
||||
- name: "Test"
|
||||
run: python3 Platforms/emscripten run --test
|
||||
9
.github/workflows/reusable-macos.yml
vendored
9
.github/workflows/reusable-macos.yml
vendored
|
|
@ -12,6 +12,9 @@ on:
|
|||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
||||
|
|
@ -28,14 +31,14 @@ jobs:
|
|||
PYTHONSTRICTEXTENSIONBUILD: 1
|
||||
TERM: linux
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Runner image version
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: Install Homebrew dependencies
|
||||
run: |
|
||||
brew install pkg-config openssl@3.0 xz gdbm tcl-tk@9 make
|
||||
brew install pkg-config openssl@3.5 xz gdbm tcl-tk@9 make
|
||||
# Because alternate versions are not symlinked into place by default:
|
||||
brew link --overwrite tcl-tk@9
|
||||
- name: Configure CPython
|
||||
|
|
@ -50,7 +53,7 @@ jobs:
|
|||
--enable-safety \
|
||||
${{ inputs.free-threading && '--disable-gil' || '' }} \
|
||||
--prefix=/opt/python-dev \
|
||||
--with-openssl="$(brew --prefix openssl@3.0)"
|
||||
--with-openssl="$(brew --prefix openssl@3.5)"
|
||||
- name: Build CPython
|
||||
if : ${{ inputs.free-threading || inputs.os != 'macos-15-intel' }}
|
||||
run: gmake -j8
|
||||
|
|
|
|||
29
.github/workflows/reusable-san.yml
vendored
29
.github/workflows/reusable-san.yml
vendored
|
|
@ -12,6 +12,9 @@ on:
|
|||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
||||
|
|
@ -26,7 +29,7 @@ jobs:
|
|||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Runner image version
|
||||
|
|
@ -37,17 +40,15 @@ jobs:
|
|||
# Install clang
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 20
|
||||
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-20 100
|
||||
sudo update-alternatives --set clang /usr/bin/clang-20
|
||||
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-20 100
|
||||
sudo update-alternatives --set clang++ /usr/bin/clang++-20
|
||||
|
||||
if [ "${SANITIZER}" = "TSan" ]; then
|
||||
sudo ./llvm.sh 17 # gh-121946: llvm-18 package is temporarily broken
|
||||
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-17 100
|
||||
sudo update-alternatives --set clang /usr/bin/clang-17
|
||||
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-17 100
|
||||
sudo update-alternatives --set clang++ /usr/bin/clang++-17
|
||||
# Reduce ASLR to avoid TSan crashing
|
||||
sudo sysctl -w vm.mmap_rnd_bits=28
|
||||
else
|
||||
sudo ./llvm.sh 20
|
||||
fi
|
||||
|
||||
- name: Sanitizer option setup
|
||||
|
|
@ -59,16 +60,13 @@ jobs:
|
|||
|| ''
|
||||
}}.txt handle_segv=0" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "UBSAN_OPTIONS=${SAN_LOG_OPTION}" >> "$GITHUB_ENV"
|
||||
echo "UBSAN_OPTIONS=${SAN_LOG_OPTION} halt_on_error=1 suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" >> "$GITHUB_ENV"
|
||||
fi
|
||||
echo "CC=clang" >> "$GITHUB_ENV"
|
||||
echo "CXX=clang++" >> "$GITHUB_ENV"
|
||||
env:
|
||||
SANITIZER: ${{ inputs.sanitizer }}
|
||||
SAN_LOG_OPTION: log_path=${{ github.workspace }}/san_log
|
||||
- name: Add ccache to PATH
|
||||
run: |
|
||||
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: Configure CPython
|
||||
run: >-
|
||||
./configure
|
||||
|
|
@ -76,7 +74,7 @@ jobs:
|
|||
${{
|
||||
inputs.sanitizer == 'TSan'
|
||||
&& '--with-thread-sanitizer'
|
||||
|| '--with-undefined-behavior-sanitizer'
|
||||
|| '--with-undefined-behavior-sanitizer --with-strict-overflow'
|
||||
}}
|
||||
--with-pydebug
|
||||
${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
|
||||
|
|
@ -84,10 +82,13 @@ jobs:
|
|||
run: make -j4
|
||||
- name: Display build info
|
||||
run: make pythoninfo
|
||||
# test_{capi,faulthandler} are skipped under UBSan because
|
||||
# they raise signals that UBSan with halt_on_error=1 intercepts.
|
||||
- name: Tests
|
||||
run: >-
|
||||
./python -m test
|
||||
${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }}
|
||||
${{ inputs.sanitizer == 'UBSan' && '-x test_capi -x test_faulthandler' || '' }}
|
||||
-j4
|
||||
- name: Parallel tests
|
||||
if: >-
|
||||
|
|
@ -99,7 +100,7 @@ jobs:
|
|||
run: find "${GITHUB_WORKSPACE}" -name 'san_log.*' | xargs head -n 1000
|
||||
- name: Archive logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: >-
|
||||
${{ inputs.sanitizer }}-logs-${{
|
||||
|
|
|
|||
23
.github/workflows/reusable-ubuntu.yml
vendored
23
.github/workflows/reusable-ubuntu.yml
vendored
|
|
@ -17,6 +17,14 @@ on:
|
|||
description: OS to run the job
|
||||
required: true
|
||||
type: string
|
||||
test-opts:
|
||||
description: Extra options to pass to the test runner via TESTOPTS
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
|
@ -27,11 +35,11 @@ jobs:
|
|||
runs-on: ${{ inputs.os }}
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
OPENSSL_VER: 3.0.18
|
||||
OPENSSL_VER: 3.5.5
|
||||
PYTHONSTRICTEXTENSIONBUILD: 1
|
||||
TERM: linux
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Register gcc problem matcher
|
||||
|
|
@ -42,7 +50,7 @@ jobs:
|
|||
if: ${{ fromJSON(inputs.bolt-optimizations) }}
|
||||
run: |
|
||||
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh 19
|
||||
sudo apt-get install bolt-19
|
||||
sudo apt-get install --no-install-recommends bolt-19
|
||||
echo PATH="$(llvm-config-19 --bindir):$PATH" >> $GITHUB_ENV
|
||||
- name: Configure OpenSSL env vars
|
||||
run: |
|
||||
|
|
@ -51,16 +59,13 @@ jobs:
|
|||
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
|
||||
- name: 'Restore OpenSSL build'
|
||||
id: cache-openssl
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
|
||||
key: ${{ inputs.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
|
||||
- name: Install OpenSSL
|
||||
if: steps.cache-openssl.outputs.cache-hit != 'true'
|
||||
run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux
|
||||
- name: Add ccache to PATH
|
||||
run: |
|
||||
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: Setup directory envs for out-of-tree builds
|
||||
run: |
|
||||
echo "CPYTHON_RO_SRCDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-ro-srcdir)" >> "$GITHUB_ENV"
|
||||
|
|
@ -111,4 +116,6 @@ jobs:
|
|||
run: sudo mount "$CPYTHON_RO_SRCDIR" -oremount,rw
|
||||
- name: Tests
|
||||
working-directory: ${{ env.CPYTHON_BUILDDIR }}
|
||||
run: xvfb-run make ci
|
||||
run: xvfb-run make ci EXTRATESTOPTS="${TEST_OPTS}"
|
||||
env:
|
||||
TEST_OPTS: ${{ inputs.test-opts }}
|
||||
|
|
|
|||
42
.github/workflows/reusable-wasi.yml
vendored
42
.github/workflows/reusable-wasi.yml
vendored
|
|
@ -3,6 +3,9 @@ name: Reusable WASI
|
|||
on:
|
||||
workflow_call:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
||||
|
|
@ -13,35 +16,36 @@ jobs:
|
|||
timeout-minutes: 60
|
||||
env:
|
||||
WASMTIME_VERSION: 38.0.3
|
||||
WASI_SDK_VERSION: 29
|
||||
WASI_SDK_PATH: /opt/wasi-sdk
|
||||
CROSS_BUILD_PYTHON: cross-build/build
|
||||
CROSS_BUILD_WASI: cross-build/wasm32-wasip1
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
# No problem resolver registered as one doesn't currently exist for Clang.
|
||||
- name: "Install wasmtime"
|
||||
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||
uses: bytecodealliance/actions/wasmtime/setup@9152e710e9f7182e4c29ad218e4f335a7b203613 # v1.1.3
|
||||
with:
|
||||
version: ${{ env.WASMTIME_VERSION }}
|
||||
- name: "Restore WASI SDK"
|
||||
id: cache-wasi-sdk
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ env.WASI_SDK_PATH }}
|
||||
key: ${{ runner.os }}-wasi-sdk-${{ env.WASI_SDK_VERSION }}
|
||||
- name: "Install WASI SDK" # Hard-coded to x64.
|
||||
if: steps.cache-wasi-sdk.outputs.cache-hit != 'true'
|
||||
- name: "Read WASI SDK version"
|
||||
id: wasi-sdk-version
|
||||
run: |
|
||||
mkdir "${WASI_SDK_PATH}" && \
|
||||
curl -s -S --location "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_VERSION}.0-arm64-linux.tar.gz" | \
|
||||
tar --strip-components 1 --directory "${WASI_SDK_PATH}" --extract --gunzip
|
||||
- name: "Add ccache to PATH"
|
||||
run: echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
import os
|
||||
config = tomllib.loads(Path("Platforms/WASI/config.toml").read_text())
|
||||
version = config["targets"]["wasi-sdk"]
|
||||
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
|
||||
f.write(f"version={version}\n")
|
||||
shell: python
|
||||
- name: "Install WASI SDK"
|
||||
id: install-wasi-sdk
|
||||
uses: bytecodealliance/setup-wasi-sdk-action@b2de090b44eb70013ee96b393727d473b35e1728
|
||||
with:
|
||||
version: ${{ steps.wasi-sdk-version.outputs.version }}
|
||||
add-to-path: false
|
||||
- name: "Install Python"
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: "Runner image version"
|
||||
|
|
@ -53,6 +57,8 @@ jobs:
|
|||
- name: "Configure host"
|
||||
# `--with-pydebug` inferred from configure-build-python
|
||||
run: python3 Platforms/WASI configure-host -- --config-cache
|
||||
env:
|
||||
WASI_SDK_PATH: ${{ steps.install-wasi-sdk.outputs.wasi-sdk-path }}
|
||||
- name: "Make host"
|
||||
run: python3 Platforms/WASI make-host
|
||||
- name: "Display build info"
|
||||
|
|
|
|||
4
.github/workflows/reusable-windows-msi.yml
vendored
4
.github/workflows/reusable-windows-msi.yml
vendored
|
|
@ -17,13 +17,13 @@ env:
|
|||
jobs:
|
||||
build:
|
||||
name: installer for ${{ inputs.arch }}
|
||||
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2022' }}
|
||||
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2025-vs2026' }}
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
ARCH: ${{ inputs.arch }}
|
||||
IncludeFreethreaded: true
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Build CPython installer
|
||||
|
|
|
|||
21
.github/workflows/reusable-windows.yml
vendored
21
.github/workflows/reusable-windows.yml
vendored
|
|
@ -12,6 +12,13 @@ on:
|
|||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
interpreter:
|
||||
description: Which interpreter to build (switch-case or tail-call)
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
|
@ -20,22 +27,25 @@ env:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and test (${{ inputs.arch }})
|
||||
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2022' }}
|
||||
name: Build and test (${{ inputs.arch }}, ${{ inputs.interpreter }})
|
||||
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2025-vs2026' }}
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
ARCH: ${{ inputs.arch }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Register MSVC problem matcher
|
||||
if: inputs.arch != 'Win32'
|
||||
run: echo "::add-matcher::.github/problem-matchers/msvc.json"
|
||||
- name: Build CPython
|
||||
# msvc::musttail is not supported for debug builds, so we have to
|
||||
# switch to release.
|
||||
run: >-
|
||||
.\\PCbuild\\build.bat
|
||||
-e -d -v
|
||||
-e -v
|
||||
${{ inputs.interpreter == 'switch-case' && '-d' || '--tail-call-interp -c Release' }}
|
||||
-p "${ARCH}"
|
||||
${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
|
||||
shell: bash
|
||||
|
|
@ -45,6 +55,7 @@ jobs:
|
|||
run: >-
|
||||
.\\PCbuild\\rt.bat
|
||||
-p "${ARCH}"
|
||||
-d -q --fast-ci
|
||||
-q --fast-ci
|
||||
${{ inputs.interpreter == 'switch-case' && '-d' || '' }}
|
||||
${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
|
||||
shell: bash
|
||||
|
|
|
|||
6
.github/workflows/stale.yml
vendored
6
.github/workflows/stale.yml
vendored
|
|
@ -4,17 +4,21 @@ on:
|
|||
schedule:
|
||||
- cron: "0 */6 * * *"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
if: github.repository_owner == 'python'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: write
|
||||
pull-requests: write
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: "Check PRs"
|
||||
uses: actions/stale@v9
|
||||
uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity.'
|
||||
|
|
|
|||
131
.github/workflows/tail-call.yml
vendored
131
.github/workflows/tail-call.yml
vendored
|
|
@ -1,19 +1,14 @@
|
|||
name: Tail calling interpreter
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
paths: &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'
|
||||
- 'Python/generated_cases.c.h'
|
||||
paths: *paths
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
|
|
@ -25,107 +20,73 @@ concurrency:
|
|||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
LLVM_VERSION: 21
|
||||
|
||||
jobs:
|
||||
tail-call:
|
||||
macos:
|
||||
name: ${{ matrix.target }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
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
|
||||
# - aarch64-pc-windows-msvc/msvc
|
||||
- x86_64-apple-darwin/clang
|
||||
- aarch64-apple-darwin/clang
|
||||
- x86_64-unknown-linux-gnu/gcc
|
||||
- aarch64-unknown-linux-gnu/gcc
|
||||
- free-threading
|
||||
llvm:
|
||||
- 20
|
||||
include:
|
||||
# - target: i686-pc-windows-msvc/msvc
|
||||
# architecture: Win32
|
||||
# runner: windows-2022
|
||||
- target: x86_64-pc-windows-msvc/msvc
|
||||
architecture: x64
|
||||
runner: windows-2022
|
||||
# - target: aarch64-pc-windows-msvc/msvc
|
||||
# architecture: ARM64
|
||||
# runner: windows-2022
|
||||
- target: x86_64-apple-darwin/clang
|
||||
architecture: x86_64
|
||||
runner: macos-15-intel
|
||||
- target: aarch64-apple-darwin/clang
|
||||
architecture: aarch64
|
||||
runner: macos-14
|
||||
- target: x86_64-unknown-linux-gnu/gcc
|
||||
architecture: x86_64
|
||||
runner: ubuntu-24.04
|
||||
- target: aarch64-unknown-linux-gnu/gcc
|
||||
architecture: aarch64
|
||||
runner: ubuntu-24.04-arm
|
||||
- target: free-threading
|
||||
architecture: x86_64
|
||||
runner: ubuntu-24.04
|
||||
runner: macos-15
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v6
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Native Windows MSVC (release)
|
||||
if: runner.os == 'Windows' && matrix.architecture != 'ARM64'
|
||||
shell: pwsh
|
||||
run: |
|
||||
choco install visualstudio2026buildtools --no-progress -y --force --params "--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --locale en-US --passive"
|
||||
$env:PATH = "C:\Program Files (x86)\Microsoft Visual Studio\18\BuildTools\MSBuild\Current\bin;$env:PATH"
|
||||
$env:PlatformToolset = "v145"
|
||||
./PCbuild/build.bat --tail-call-interp -c Release -p ${{ matrix.architecture }}
|
||||
./PCbuild/rt.bat -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
|
||||
|
||||
# No tests (yet):
|
||||
- name: Emulated Windows Clang (release)
|
||||
if: runner.os == 'Windows' && matrix.architecture == 'ARM64'
|
||||
shell: pwsh
|
||||
run: |
|
||||
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
|
||||
$env:PlatformToolset = "clangcl"
|
||||
$env:LLVMToolsVersion = "${{ matrix.llvm }}.1.0"
|
||||
$env:LLVMInstallDir = "C:\Program Files\LLVM"
|
||||
./PCbuild/build.bat --tail-call-interp -p ${{ matrix.architecture }}
|
||||
|
||||
- name: Native macOS (release)
|
||||
if: runner.os == 'macOS'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew update
|
||||
brew install llvm@${{ matrix.llvm }}
|
||||
brew install llvm@${{ env.LLVM_VERSION }}
|
||||
- name: Build
|
||||
run: |
|
||||
export SDKROOT="$(xcrun --show-sdk-path)"
|
||||
export PATH="/usr/local/opt/llvm@${{ matrix.llvm }}/bin:$PATH"
|
||||
export PATH="/opt/homebrew/opt/llvm@${{ matrix.llvm }}/bin:$PATH"
|
||||
CC=clang-20 ./configure --with-tail-call-interp
|
||||
export PATH="/usr/local/opt/llvm@${{ env.LLVM_VERSION }}/bin:$PATH"
|
||||
export PATH="/opt/homebrew/opt/llvm@${{ env.LLVM_VERSION }}/bin:$PATH"
|
||||
CC=clang-${{ env.LLVM_VERSION }} ./configure --with-tail-call-interp
|
||||
make all --jobs 4
|
||||
- name: Test
|
||||
run: |
|
||||
./python.exe -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
|
||||
|
||||
- name: Native Linux (debug)
|
||||
if: runner.os == 'Linux' && matrix.target != 'free-threading'
|
||||
linux:
|
||||
name: ${{ matrix.target }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-unknown-linux-gnu/gcc
|
||||
runner: ubuntu-24.04
|
||||
configure_flags: --with-pydebug
|
||||
- target: x86_64-unknown-linux-gnu/gcc-free-threading
|
||||
runner: ubuntu-24.04
|
||||
configure_flags: --disable-gil
|
||||
- target: aarch64-unknown-linux-gnu/gcc
|
||||
runner: ubuntu-24.04-arm
|
||||
configure_flags: --with-pydebug
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Build
|
||||
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-20 ./configure --with-tail-call-interp --with-pydebug
|
||||
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ env.LLVM_VERSION }}
|
||||
export PATH="$(llvm-config-${{ env.LLVM_VERSION }} --bindir):$PATH"
|
||||
CC=clang-${{ env.LLVM_VERSION }} ./configure --with-tail-call-interp ${{ matrix.configure_flags }}
|
||||
make all --jobs 4
|
||||
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
|
||||
|
||||
- name: Native Linux with free-threading (release)
|
||||
if: matrix.target == 'free-threading'
|
||||
- name: Test
|
||||
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-20 ./configure --with-tail-call-interp --disable-gil
|
||||
make all --jobs 4
|
||||
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
|
||||
|
|
|
|||
|
|
@ -25,10 +25,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v6
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3'
|
||||
- name: Compare checksum of bundled wheels to the ones published on PyPI
|
||||
|
|
|
|||
32
.github/workflows/verify-expat.yml
vendored
Normal file
32
.github/workflows/verify-expat.yml
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
name: Verify bundled libexpat
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- 'Modules/expat/**'
|
||||
- '.github/workflows/verify-expat.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'Modules/expat/**'
|
||||
- '.github/workflows/verify-expat.yml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Download and verify bundled libexpat files
|
||||
run: |
|
||||
./Modules/expat/refresh.sh
|
||||
git diff --exit-code Modules/expat/
|
||||
6
.github/zizmor.yml
vendored
6
.github/zizmor.yml
vendored
|
|
@ -1,10 +1,6 @@
|
|||
# Configuration for the zizmor static analysis tool, run via prek in CI
|
||||
# https://woodruffw.github.io/zizmor/configuration/
|
||||
# https://docs.zizmor.sh/configuration/
|
||||
rules:
|
||||
dangerous-triggers:
|
||||
ignore:
|
||||
- documentation-links.yml
|
||||
unpinned-uses:
|
||||
config:
|
||||
policies:
|
||||
"*": ref-pin
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -5,6 +5,7 @@
|
|||
*.cover
|
||||
*.iml
|
||||
*.o
|
||||
*.o.tmp
|
||||
*.lto
|
||||
*.a
|
||||
*.so
|
||||
|
|
@ -137,7 +138,7 @@ Tools/unicode/data/
|
|||
/config.status
|
||||
/config.status.lineno
|
||||
/.ccache
|
||||
/cross-build/
|
||||
/cross-build*/
|
||||
/jit_stencils*.h
|
||||
/platform
|
||||
/profile-clean-stamp
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.14.10
|
||||
rev: e05c5c0818279e5ac248ac9e954431ba58865e61 # frozen: v0.15.7
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
name: Run Ruff (lint) on Apple/
|
||||
args: [--exit-non-zero-on-fix, --config=Apple/.ruff.toml]
|
||||
files: ^Apple/
|
||||
name: Run Ruff (lint) on Platforms/Apple/
|
||||
args: [--exit-non-zero-on-fix, --config=Platforms/Apple/.ruff.toml]
|
||||
files: ^Platforms/Apple/
|
||||
- id: ruff-check
|
||||
name: Run Ruff (lint) on Doc/
|
||||
args: [--exit-non-zero-on-fix]
|
||||
|
|
@ -14,6 +14,10 @@ repos:
|
|||
name: Run Ruff (lint) on Lib/test/
|
||||
args: [--exit-non-zero-on-fix]
|
||||
files: ^Lib/test/
|
||||
- id: ruff-check
|
||||
name: Run Ruff (lint) on Platforms/WASI/
|
||||
args: [--exit-non-zero-on-fix, --config=Platforms/WASI/.ruff.toml]
|
||||
files: ^Platforms/WASI/
|
||||
- id: ruff-check
|
||||
name: Run Ruff (lint) on Tools/build/
|
||||
args: [--exit-non-zero-on-fix, --config=Tools/build/.ruff.toml]
|
||||
|
|
@ -35,13 +39,17 @@ repos:
|
|||
args: [--exit-non-zero-on-fix, --config=Tools/wasm/.ruff.toml]
|
||||
files: ^Tools/wasm/
|
||||
- id: ruff-format
|
||||
name: Run Ruff (format) on Apple/
|
||||
args: [--exit-non-zero-on-fix, --config=Apple/.ruff.toml]
|
||||
files: ^Apple
|
||||
name: Run Ruff (format) on Platforms/Apple/
|
||||
args: [--exit-non-zero-on-fix, --config=Platforms/Apple/.ruff.toml]
|
||||
files: ^Platforms/Apple/
|
||||
- id: ruff-format
|
||||
name: Run Ruff (format) on Doc/
|
||||
args: [--exit-non-zero-on-fix]
|
||||
files: ^Doc/
|
||||
- id: ruff-format
|
||||
name: Run Ruff (format) on Platforms/WASI/
|
||||
args: [--exit-non-zero-on-fix, --config=Platforms/WASI/.ruff.toml]
|
||||
files: ^Platforms/WASI/
|
||||
- id: ruff-format
|
||||
name: Run Ruff (format) on Tools/build/check_warnings.py
|
||||
args: [--exit-non-zero-on-fix, --config=Tools/build/.ruff.toml]
|
||||
|
|
@ -52,20 +60,20 @@ repos:
|
|||
files: ^Tools/wasm/
|
||||
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 25.12.0
|
||||
rev: ea488cebbfd88a5f50b8bd95d5c829d0bb76feb8 # frozen: 26.1.0
|
||||
hooks:
|
||||
- id: black
|
||||
name: Run Black on Tools/jit/
|
||||
files: ^Tools/jit/
|
||||
|
||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
||||
rev: v1.5.5
|
||||
rev: ad1b27d73581aa16cca06fc4a0761fc563ffe8e8 # frozen: v1.5.6
|
||||
hooks:
|
||||
- id: remove-tabs
|
||||
types: [python]
|
||||
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v6.0.0
|
||||
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0
|
||||
hooks:
|
||||
- id: check-case-conflict
|
||||
- id: check-merge-conflict
|
||||
|
|
@ -77,30 +85,33 @@ repos:
|
|||
exclude: Lib/test/tokenizedata/coding20731.py
|
||||
- id: end-of-file-fixer
|
||||
files: '^\.github/CODEOWNERS$'
|
||||
- id: mixed-line-ending
|
||||
args: [--fix=auto]
|
||||
exclude: '^Lib/test/.*data/'
|
||||
- id: trailing-whitespace
|
||||
types_or: [c, inc, python, rst, yaml]
|
||||
- id: trailing-whitespace
|
||||
files: '^\.github/CODEOWNERS|\.(gram)$'
|
||||
|
||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||
rev: 0.36.0
|
||||
rev: 9f48a48aa91a6040d749ad68ec70907d907a5a7f # frozen: 0.37.0
|
||||
hooks:
|
||||
- id: check-dependabot
|
||||
- id: check-github-workflows
|
||||
- id: check-readthedocs
|
||||
|
||||
- repo: https://github.com/rhysd/actionlint
|
||||
rev: v1.7.9
|
||||
rev: 393031adb9afb225ee52ae2ccd7a5af5525e03e8 # frozen: v1.7.11
|
||||
hooks:
|
||||
- id: actionlint
|
||||
|
||||
- repo: https://github.com/woodruffw/zizmor-pre-commit
|
||||
rev: v1.19.0
|
||||
- repo: https://github.com/zizmorcore/zizmor-pre-commit
|
||||
rev: b546b77c44c466a54a42af5499dcc0dcc1a3193f # frozen: v1.22.0
|
||||
hooks:
|
||||
- id: zizmor
|
||||
|
||||
- repo: https://github.com/sphinx-contrib/sphinx-lint
|
||||
rev: v1.0.2
|
||||
rev: c883505f64b59c3c5c9375191e4ad9f98e727ccd # frozen: v1.0.2
|
||||
hooks:
|
||||
- id: sphinx-lint
|
||||
args: [--enable=default-role]
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ ignore = [
|
|||
"E501", # Ignore line length errors (we use auto-formatting)
|
||||
]
|
||||
|
||||
[lint.per-file-ignores]
|
||||
"tools/check-html-ids.py" = ["I001"] # Unsorted imports
|
||||
|
||||
[format]
|
||||
preview = true
|
||||
quote-style = "preserve"
|
||||
|
|
|
|||
15
Doc/Makefile
15
Doc/Makefile
|
|
@ -58,7 +58,7 @@ build:
|
|||
@if [ -f ../Misc/NEWS ] ; then \
|
||||
echo "Using existing Misc/NEWS file"; \
|
||||
cp ../Misc/NEWS build/NEWS; \
|
||||
elif $(BLURB) help >/dev/null 2>&1 && $(SPHINXBUILD) --version >/dev/null 2>&1; then \
|
||||
elif $(BLURB) --version && $(SPHINXBUILD) --version ; then \
|
||||
if [ -d ../Misc/NEWS.d ]; then \
|
||||
echo "Building NEWS from Misc/NEWS.d with blurb"; \
|
||||
$(BLURB) merge -f build/NEWS; \
|
||||
|
|
@ -88,6 +88,7 @@ htmlhelp: build
|
|||
"build/htmlhelp/pydoc.hhp project file."
|
||||
|
||||
.PHONY: latex
|
||||
latex: _ensure-sphinxcontrib-svg2pdfconverter
|
||||
latex: BUILDER = latex
|
||||
latex: build
|
||||
@echo "Build finished; the LaTeX files are in build/latex."
|
||||
|
|
@ -231,7 +232,7 @@ dist-text:
|
|||
@echo "Build finished and archived!"
|
||||
|
||||
.PHONY: dist-pdf
|
||||
dist-pdf:
|
||||
dist-pdf: _ensure-sphinxcontrib-svg2pdfconverter
|
||||
# archive the A4 latex
|
||||
@echo "Building LaTeX (A4 paper)..."
|
||||
mkdir -p dist
|
||||
|
|
@ -292,6 +293,10 @@ _ensure-pre-commit:
|
|||
_ensure-sphinx-autobuild:
|
||||
$(MAKE) _ensure-package PACKAGE=sphinx-autobuild
|
||||
|
||||
.PHONY: _ensure-sphinxcontrib-svg2pdfconverter
|
||||
_ensure-sphinxcontrib-svg2pdfconverter:
|
||||
$(MAKE) _ensure-package PACKAGE=sphinxcontrib-svg2pdfconverter
|
||||
|
||||
.PHONY: check
|
||||
check: _ensure-pre-commit
|
||||
$(VENVDIR)/bin/python3 -m pre_commit run --all-files
|
||||
|
|
@ -336,3 +341,9 @@ autobuild-stable-html:
|
|||
exit 1;; \
|
||||
esac
|
||||
@$(MAKE) autobuild-dev-html
|
||||
|
||||
# Collect HTML IDs to a JSON document
|
||||
.PHONY: html-ids
|
||||
html-ids:
|
||||
$(PYTHON) tools/check-html-ids.py collect build/html \
|
||||
-o build/html/html-ids.json.gz
|
||||
|
|
|
|||
570
Doc/_static/profiling-sampling-visualization.css
Normal file
570
Doc/_static/profiling-sampling-visualization.css
Normal file
|
|
@ -0,0 +1,570 @@
|
|||
/**
|
||||
* Sampling Profiler Visualization - Scoped CSS
|
||||
*/
|
||||
|
||||
.sampling-profiler-viz {
|
||||
/* Match docs background colors */
|
||||
--bg-page: #ffffff;
|
||||
--bg-panel: #ffffff;
|
||||
--bg-subtle: #f8f8f8;
|
||||
--bg-code: #f8f8f8;
|
||||
|
||||
/* Match docs border style */
|
||||
--border-color: #e1e4e8;
|
||||
--border-accent: #3776ab;
|
||||
|
||||
/* Match docs text colors */
|
||||
--text-primary: #0d0d0d;
|
||||
--text-secondary: #505050;
|
||||
--text-muted: #6e6e6e;
|
||||
--text-code: #333333;
|
||||
|
||||
/* Accent colors */
|
||||
--color-python-blue: #306998;
|
||||
--color-green: #388e3c;
|
||||
--color-orange: #e65100;
|
||||
--color-purple: #7b1fa2;
|
||||
--color-red: #c62828;
|
||||
--color-teal: #00897b;
|
||||
--color-yellow: #d4a910;
|
||||
--color-highlight: #fff9e6;
|
||||
|
||||
--radius-lg: 8px;
|
||||
--radius-md: 6px;
|
||||
--radius-sm: 4px;
|
||||
|
||||
/* Lighter shadows to match docs style */
|
||||
--shadow-card: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
|
||||
--container-height: 520px;
|
||||
--code-panel-width: 320px;
|
||||
|
||||
/* Reset for isolation */
|
||||
font-family: var(--font-ui);
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
color: var(--text-primary);
|
||||
background-color: var(--bg-page);
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
/* Layout */
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 920px;
|
||||
height: var(--container-height);
|
||||
display: grid;
|
||||
grid-template-columns: var(--code-panel-width) 1fr;
|
||||
margin: 24px auto;
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow-card);
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--bg-panel);
|
||||
/* Prevent any DOM changes inside from affecting page scroll */
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Code Panel - Left Column */
|
||||
.sampling-profiler-viz #code-panel {
|
||||
background: var(--bg-panel);
|
||||
border-right: 1px solid var(--border-color);
|
||||
overflow-y: auto;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel .code-panel-title {
|
||||
padding: 12px 16px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
background: var(--bg-code);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel .code-container {
|
||||
margin: 0;
|
||||
padding: 12px 0;
|
||||
overflow-x: auto;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel .line {
|
||||
display: flex;
|
||||
padding: 1px 0;
|
||||
min-height: 20px;
|
||||
transition: background-color 0.1s ease;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel .line-number {
|
||||
color: var(--text-muted);
|
||||
min-width: 40px;
|
||||
text-align: right;
|
||||
padding-right: 12px;
|
||||
padding-left: 12px;
|
||||
user-select: none;
|
||||
flex-shrink: 0;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel .line-content {
|
||||
flex: 1;
|
||||
color: var(--text-code);
|
||||
padding-right: 12px;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel .line.highlighted {
|
||||
background: var(--color-highlight);
|
||||
border-left: 3px solid var(--color-yellow);
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel .line.highlighted .line-number {
|
||||
color: var(--color-yellow);
|
||||
padding-left: 9px;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel .line.highlighted .line-content {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Python Syntax Highlighting */
|
||||
.sampling-profiler-viz #code-panel .keyword {
|
||||
color: var(--color-red);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel .function {
|
||||
color: var(--color-purple);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel .number {
|
||||
color: var(--color-python-blue);
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel .string {
|
||||
color: #032f62;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel .comment {
|
||||
color: #6a737d;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel .builtin {
|
||||
color: var(--color-python-blue);
|
||||
}
|
||||
|
||||
/* Visualization Column - Right Side */
|
||||
.sampling-profiler-viz .viz-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--bg-subtle);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Stack Section */
|
||||
.sampling-profiler-viz .stack-section {
|
||||
padding: 12px 16px;
|
||||
flex: 1;
|
||||
min-height: 150px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .stack-section-title {
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .stack-visualization {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
/* Stack Frames - Vertical Layout */
|
||||
.sampling-profiler-viz .stack-frame {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
contain: layout style paint;
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .stack-frame.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
transition:
|
||||
opacity 0.3s ease,
|
||||
transform 0.3s ease;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .stack-frame-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: var(--radius-sm);
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .stack-frame-text {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font: 500 11px var(--font-mono);
|
||||
color: white;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .stack-frame-flash {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: white;
|
||||
border-radius: var(--radius-sm);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .stack-frame:hover .stack-frame-bg {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
/* Flying frames */
|
||||
.sampling-profiler-viz .stack-frame.flying {
|
||||
pointer-events: none;
|
||||
z-index: 1000;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: auto;
|
||||
height: 32px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Flying stack clone */
|
||||
.stack-visualization.flying-clone {
|
||||
transform-origin: center center;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
/* Sampling Panel */
|
||||
.sampling-profiler-viz .sampling-panel {
|
||||
margin: 0 16px 12px 16px;
|
||||
background: var(--bg-panel);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-sm);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 0 0 auto;
|
||||
height: 200px;
|
||||
/* Lock font size to prevent Sphinx responsive scaling */
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .sampling-header {
|
||||
padding: 8px 10px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .sampling-title {
|
||||
font: 600 10px var(--font-mono);
|
||||
color: var(--text-primary);
|
||||
margin: 0 0 3px 0;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .sampling-stats {
|
||||
font: 400 9px var(--font-mono);
|
||||
color: var(--text-secondary);
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .sampling-stats .missed {
|
||||
color: var(--color-red);
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .sampling-bars {
|
||||
flex: 1;
|
||||
padding: 10px 12px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .sampling-bar-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 22px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .bar-label {
|
||||
font: 500 8px var(--font-mono);
|
||||
color: var(--text-primary);
|
||||
flex-shrink: 0;
|
||||
width: 60px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .bar-container {
|
||||
flex: 1;
|
||||
height: 12px;
|
||||
background: var(--border-color);
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .bar-fill {
|
||||
height: 100%;
|
||||
border-radius: 3px;
|
||||
transition: width 0.2s ease;
|
||||
min-width: 2px;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .bar-percent {
|
||||
font: 500 8px var(--font-mono);
|
||||
color: var(--text-secondary);
|
||||
width: 36px;
|
||||
text-align: right;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Impact effect circle */
|
||||
.impact-circle {
|
||||
position: fixed;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-teal);
|
||||
transform: translate(-50%, -50%);
|
||||
pointer-events: none;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
/* Control Panel - Integrated */
|
||||
.sampling-profiler-viz #control-panel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 12px 16px;
|
||||
background: var(--bg-panel);
|
||||
border-top: 1px solid var(--border-color);
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .control-group {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .control-group label {
|
||||
font-size: 10px;
|
||||
color: var(--text-muted);
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .control-btn {
|
||||
background: var(--bg-panel);
|
||||
color: var(--text-primary);
|
||||
border: 1px solid var(--border-color);
|
||||
padding: 6px 10px;
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .control-btn:hover {
|
||||
background: var(--bg-subtle);
|
||||
border-color: var(--text-muted);
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .control-btn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .control-btn.active {
|
||||
background: var(--color-python-blue);
|
||||
color: white;
|
||||
border-color: var(--color-python-blue);
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .control-btn.active:hover {
|
||||
background: #2f6493;
|
||||
}
|
||||
|
||||
/* Timeline Scrubber */
|
||||
.sampling-profiler-viz .timeline-scrubber {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-width: 160px;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #timeline-scrubber {
|
||||
flex: 1;
|
||||
height: 5px;
|
||||
border-radius: 3px;
|
||||
background: var(--border-color);
|
||||
outline: none;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
cursor: pointer;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #timeline-scrubber::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-python-blue);
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #timeline-scrubber::-webkit-slider-thumb:hover {
|
||||
transform: scale(1.15);
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #timeline-scrubber::-moz-range-thumb {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-python-blue);
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #time-display {
|
||||
font: 500 10px var(--font-mono);
|
||||
color: var(--text-secondary);
|
||||
min-width: 90px;
|
||||
text-align: right;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Sample Interval Slider */
|
||||
.sampling-profiler-viz #sample-interval {
|
||||
width: 80px;
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
background: var(--border-color);
|
||||
outline: none;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #sample-interval::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-teal);
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #sample-interval::-webkit-slider-thumb:hover {
|
||||
transform: scale(1.15);
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #sample-interval::-moz-range-thumb {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-teal);
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #interval-display {
|
||||
font: 500 9px var(--font-mono);
|
||||
color: var(--text-secondary);
|
||||
min-width: 40px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Flash overlay */
|
||||
.sampling-profiler-viz .flash-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: white;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* Performance optimizations */
|
||||
.sampling-profiler-viz .stack-frame,
|
||||
.sampling-profiler-viz .flying-frame,
|
||||
.sampling-profiler-viz .sampling-bar-row {
|
||||
will-change: transform, opacity;
|
||||
contain: layout style paint;
|
||||
}
|
||||
|
||||
/* Reduced motion support */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.sampling-profiler-viz .stack-frame,
|
||||
.sampling-profiler-viz .flying-frame,
|
||||
.sampling-profiler-viz .sampling-bar-row,
|
||||
.impact-circle {
|
||||
animation-duration: 0.01ms !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive adjustments for narrower viewports */
|
||||
@media (max-width: 800px) {
|
||||
.sampling-profiler-viz {
|
||||
grid-template-columns: 280px 1fr;
|
||||
--container-height: 550px;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz #code-panel {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.sampling-profiler-viz .control-btn {
|
||||
padding: 5px 8px;
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
1163
Doc/_static/profiling-sampling-visualization.js
Normal file
1163
Doc/_static/profiling-sampling-visualization.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -9,7 +9,7 @@ stability. In order to maintain this reputation, the developers would like to
|
|||
know of any deficiencies you find in Python.
|
||||
|
||||
It can be sometimes faster to fix bugs yourself and contribute patches to
|
||||
Python as it streamlines the process and involves less people. Learn how to
|
||||
Python as it streamlines the process and involves fewer people. Learn how to
|
||||
:ref:`contribute <contributing-to-python>`.
|
||||
|
||||
Documentation bugs
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
.. _allocating-objects:
|
||||
|
||||
Allocating Objects on the Heap
|
||||
Allocating objects on the heap
|
||||
==============================
|
||||
|
||||
|
||||
|
|
@ -153,10 +153,12 @@ Allocating Objects on the Heap
|
|||
To allocate and create extension modules.
|
||||
|
||||
|
||||
Deprecated aliases
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
Soft-deprecated aliases
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
These are :term:`soft deprecated` aliases to existing functions and macros.
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
These are aliases to existing functions and macros.
|
||||
They exist solely for backwards compatibility.
|
||||
|
||||
|
||||
|
|
@ -164,7 +166,7 @@ They exist solely for backwards compatibility.
|
|||
:widths: auto
|
||||
:header-rows: 1
|
||||
|
||||
* * Deprecated alias
|
||||
* * Soft-deprecated alias
|
||||
* Function
|
||||
* * .. c:macro:: PyObject_NEW(type, typeobj)
|
||||
* :c:macro:`PyObject_New`
|
||||
|
|
|
|||
|
|
@ -516,6 +516,28 @@ API Functions
|
|||
}
|
||||
|
||||
|
||||
.. c:function:: int PyArg_ParseArray(PyObject *const *args, Py_ssize_t nargs, const char *format, ...)
|
||||
|
||||
Parse the parameters of a function that takes only array parameters into
|
||||
local variables (that is, a function using the :c:macro:`METH_FASTCALL`
|
||||
calling convention).
|
||||
Returns true on success; on failure, it returns false and raises the
|
||||
appropriate exception.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
|
||||
.. c:function:: int PyArg_ParseArrayAndKeywords(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames, const char *format, const char * const *kwlist, ...)
|
||||
|
||||
Parse the parameters of a function that takes both array and keyword
|
||||
parameters into local variables (that is, a function using the
|
||||
:c:macro:`METH_FASTCALL` ``|`` :c:macro:`METH_KEYWORDS` calling convention).
|
||||
Returns true on success; on failure, it returns false and raises the
|
||||
appropriate exception.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
|
||||
.. c:function:: int PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...)
|
||||
|
||||
A simpler form of parameter retrieval which does not use a format string to
|
||||
|
|
|
|||
|
|
@ -10,11 +10,6 @@
|
|||
Buffer Protocol
|
||||
---------------
|
||||
|
||||
.. sectionauthor:: Greg Stein <gstein@lyra.org>
|
||||
.. sectionauthor:: Benjamin Peterson
|
||||
.. sectionauthor:: Stefan Krah
|
||||
|
||||
|
||||
Certain objects available in Python wrap access to an underlying memory
|
||||
array or *buffer*. Such objects include the built-in :class:`bytes` and
|
||||
:class:`bytearray`, and some extension types like :class:`array.array`.
|
||||
|
|
@ -263,7 +258,9 @@ readonly, format
|
|||
|
||||
.. c:macro:: PyBUF_WRITEABLE
|
||||
|
||||
This is a :term:`soft deprecated` alias to :c:macro:`PyBUF_WRITABLE`.
|
||||
This is an alias to :c:macro:`PyBUF_WRITABLE`.
|
||||
|
||||
.. soft-deprecated:: 3.13
|
||||
|
||||
.. c:macro:: PyBUF_FORMAT
|
||||
|
||||
|
|
@ -505,10 +502,11 @@ Buffer-related functions
|
|||
*indices* must point to an array of ``view->ndim`` indices.
|
||||
|
||||
|
||||
.. c:function:: int PyBuffer_FromContiguous(const Py_buffer *view, const void *buf, Py_ssize_t len, char fort)
|
||||
.. c:function:: int PyBuffer_FromContiguous(const Py_buffer *view, const void *buf, Py_ssize_t len, char order)
|
||||
|
||||
Copy contiguous *len* bytes from *buf* to *view*.
|
||||
*fort* can be ``'C'`` or ``'F'`` (for C-style or Fortran-style ordering).
|
||||
*order* can be ``'C'`` or ``'F'`` or ``'A'`` (for C-style or Fortran-style
|
||||
ordering or either one).
|
||||
``0`` is returned on success, ``-1`` on error.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,10 @@ Direct API functions
|
|||
|
||||
On failure, return ``NULL`` with an exception set.
|
||||
|
||||
.. note::
|
||||
If the object implements the buffer protocol, then the buffer
|
||||
must not be mutated while the bytearray object is being created.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyByteArray_FromStringAndSize(const char *string, Py_ssize_t len)
|
||||
|
||||
|
|
@ -58,6 +62,10 @@ Direct API functions
|
|||
|
||||
On failure, return ``NULL`` with an exception set.
|
||||
|
||||
.. note::
|
||||
If the object implements the buffer protocol, then the buffer
|
||||
must not be mutated while the bytearray object is being created.
|
||||
|
||||
|
||||
.. c:function:: Py_ssize_t PyByteArray_Size(PyObject *bytearray)
|
||||
|
||||
|
|
@ -70,6 +78,9 @@ Direct API functions
|
|||
``NULL`` pointer. The returned array always has an extra
|
||||
null byte appended.
|
||||
|
||||
.. note::
|
||||
It is not thread-safe to mutate the bytearray object while using the returned char array.
|
||||
|
||||
|
||||
.. c:function:: int PyByteArray_Resize(PyObject *bytearray, Py_ssize_t len)
|
||||
|
||||
|
|
@ -89,6 +100,9 @@ These macros trade safety for speed and they don't check pointers.
|
|||
|
||||
Similar to :c:func:`PyByteArray_AsString`, but without error checking.
|
||||
|
||||
.. note::
|
||||
It is not thread-safe to mutate the bytearray object while using the returned char array.
|
||||
|
||||
|
||||
.. c:function:: Py_ssize_t PyByteArray_GET_SIZE(PyObject *bytearray)
|
||||
|
||||
|
|
|
|||
|
|
@ -47,9 +47,9 @@ called with a non-bytes parameter.
|
|||
*len* on success, and ``NULL`` on failure. If *v* is ``NULL``, the contents of
|
||||
the bytes object are uninitialized.
|
||||
|
||||
.. deprecated:: 3.15
|
||||
``PyBytes_FromStringAndSize(NULL, len)`` is :term:`soft deprecated`,
|
||||
use the :c:type:`PyBytesWriter` API instead.
|
||||
.. soft-deprecated:: 3.15
|
||||
Use the :c:type:`PyBytesWriter` API instead of
|
||||
``PyBytes_FromStringAndSize(NULL, len)``.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyBytes_FromFormat(const char *format, ...)
|
||||
|
|
@ -127,6 +127,10 @@ called with a non-bytes parameter.
|
|||
Return the bytes representation of object *o* that implements the buffer
|
||||
protocol.
|
||||
|
||||
.. note::
|
||||
If the object implements the buffer protocol, then the buffer
|
||||
must not be mutated while the bytes object is being created.
|
||||
|
||||
|
||||
.. c:function:: Py_ssize_t PyBytes_Size(PyObject *o)
|
||||
|
||||
|
|
@ -185,6 +189,9 @@ called with a non-bytes parameter.
|
|||
created, the old reference to *bytes* will still be discarded and the value
|
||||
of *\*bytes* will be set to ``NULL``; the appropriate exception will be set.
|
||||
|
||||
.. note::
|
||||
If *newpart* implements the buffer protocol, then the buffer
|
||||
must not be mutated while the new bytes object is being created.
|
||||
|
||||
.. c:function:: void PyBytes_ConcatAndDel(PyObject **bytes, PyObject *newpart)
|
||||
|
||||
|
|
@ -192,6 +199,10 @@ called with a non-bytes parameter.
|
|||
appended to *bytes*. This version releases the :term:`strong reference`
|
||||
to *newpart* (i.e. decrements its reference count).
|
||||
|
||||
.. note::
|
||||
If *newpart* implements the buffer protocol, then the buffer
|
||||
must not be mutated while the new bytes object is being created.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyBytes_Join(PyObject *sep, PyObject *iterable)
|
||||
|
||||
|
|
@ -210,6 +221,9 @@ called with a non-bytes parameter.
|
|||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
.. note::
|
||||
If *iterable* objects implement the buffer protocol, then the buffers
|
||||
must not be mutated while the new bytes object is being created.
|
||||
|
||||
.. c:function:: int _PyBytes_Resize(PyObject **bytes, Py_ssize_t newsize)
|
||||
|
||||
|
|
@ -224,9 +238,8 @@ called with a non-bytes parameter.
|
|||
*\*bytes* is set to ``NULL``, :exc:`MemoryError` is set, and ``-1`` is
|
||||
returned.
|
||||
|
||||
.. deprecated:: 3.15
|
||||
The function is :term:`soft deprecated`,
|
||||
use the :c:type:`PyBytesWriter` API instead.
|
||||
.. soft-deprecated:: 3.15
|
||||
Use the :c:type:`PyBytesWriter` API instead.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyBytes_Repr(PyObject *bytes, int smartquotes)
|
||||
|
|
@ -371,6 +384,8 @@ Getters
|
|||
|
||||
Get the writer size.
|
||||
|
||||
The function cannot fail.
|
||||
|
||||
.. c:function:: void* PyBytesWriter_GetData(PyBytesWriter *writer)
|
||||
|
||||
Get the writer data: start of the internal buffer.
|
||||
|
|
@ -378,6 +393,8 @@ Getters
|
|||
The pointer is valid until :c:func:`PyBytesWriter_Finish` or
|
||||
:c:func:`PyBytesWriter_Discard` is called on *writer*.
|
||||
|
||||
The function cannot fail.
|
||||
|
||||
|
||||
Low-level API
|
||||
^^^^^^^^^^^^^
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@
|
|||
Code Objects
|
||||
------------
|
||||
|
||||
.. sectionauthor:: Jeffrey Yasskin <jyasskin@gmail.com>
|
||||
|
||||
Code objects are a low-level detail of the CPython implementation.
|
||||
Each one represents a chunk of executable code that hasn't yet been
|
||||
bound into a function.
|
||||
|
|
@ -214,7 +212,7 @@ bound into a function.
|
|||
|
||||
.. c:function:: PyObject *PyCode_Optimize(PyObject *code, PyObject *consts, PyObject *names, PyObject *lnotab_obj)
|
||||
|
||||
This is a :term:`soft deprecated` function that does nothing.
|
||||
This is a function that does nothing.
|
||||
|
||||
Prior to Python 3.10, this function would perform basic optimizations to a
|
||||
code object.
|
||||
|
|
@ -222,6 +220,8 @@ bound into a function.
|
|||
.. versionchanged:: 3.10
|
||||
This function now does nothing.
|
||||
|
||||
.. soft-deprecated:: 3.13
|
||||
|
||||
|
||||
.. _c_codeobject_flags:
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ macros.
|
|||
|
||||
This is not compatible with subinterpreters.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
|
||||
This macro is now thread safe.
|
||||
|
||||
.. c:type:: PyDateTime_CAPI
|
||||
|
||||
Structure containing the fields for the datetime C API.
|
||||
|
|
@ -44,6 +48,11 @@ macros.
|
|||
|
||||
This variable is only available once :c:macro:`PyDateTime_IMPORT` succeeds.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
|
||||
This variable should not be accessed directly as direct access is not thread-safe.
|
||||
Use :c:func:`PyDateTime_IMPORT` instead.
|
||||
|
||||
.. c:type:: PyDateTime_Date
|
||||
|
||||
This subtype of :c:type:`PyObject` represents a Python date object.
|
||||
|
|
|
|||
|
|
@ -8,13 +8,31 @@ Descriptor Objects
|
|||
"Descriptors" are objects that describe some attribute of an object. They are
|
||||
found in the dictionary of type objects.
|
||||
|
||||
.. XXX document these!
|
||||
|
||||
.. c:function:: PyObject* PyDescr_NewGetSet(PyTypeObject *type, struct PyGetSetDef *getset)
|
||||
|
||||
Create a new get-set descriptor for extension type *type* from the
|
||||
:c:type:`PyGetSetDef` structure *getset*.
|
||||
|
||||
.. c:function:: PyObject* PyDescr_NewMember(PyTypeObject *type, struct PyMemberDef *meth)
|
||||
Get-set descriptors expose attributes implemented by C getter and setter
|
||||
functions rather than stored directly in the instance. This is the same kind
|
||||
of descriptor created for entries in :c:member:`~PyTypeObject.tp_getset`, and
|
||||
it appears in Python as a :class:`types.GetSetDescriptorType` object.
|
||||
|
||||
On success, return a :term:`strong reference` to the descriptor. Return
|
||||
``NULL`` with an exception set on failure.
|
||||
|
||||
.. c:function:: PyObject* PyDescr_NewMember(PyTypeObject *type, struct PyMemberDef *member)
|
||||
|
||||
Create a new member descriptor for extension type *type* from the
|
||||
:c:type:`PyMemberDef` structure *member*.
|
||||
|
||||
Member descriptors expose fields in the type's C struct as Python
|
||||
attributes. This is the same kind of descriptor created for entries in
|
||||
:c:member:`~PyTypeObject.tp_members`, and it appears in Python as a
|
||||
:class:`types.MemberDescriptorType` object.
|
||||
|
||||
On success, return a :term:`strong reference` to the descriptor. Return
|
||||
``NULL`` with an exception set on failure.
|
||||
|
||||
.. c:var:: PyTypeObject PyMemberDescr_Type
|
||||
|
||||
|
|
@ -30,22 +48,53 @@ found in the dictionary of type objects.
|
|||
The type object for get/set descriptor objects created from
|
||||
:c:type:`PyGetSetDef` structures. These descriptors implement attributes
|
||||
whose value is computed by C getter and setter functions, and are used
|
||||
for many built-in type attributes.
|
||||
for many built-in type attributes. They correspond to
|
||||
:class:`types.GetSetDescriptorType` objects in Python.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDescr_NewMethod(PyTypeObject *type, struct PyMethodDef *meth)
|
||||
|
||||
Create a new method descriptor for extension type *type* from the
|
||||
:c:type:`PyMethodDef` structure *meth*.
|
||||
|
||||
Method descriptors expose C functions as methods on a type. This is the same
|
||||
kind of descriptor created for entries in
|
||||
:c:member:`~PyTypeObject.tp_methods`, and it appears in Python as a
|
||||
:class:`types.MethodDescriptorType` object.
|
||||
|
||||
On success, return a :term:`strong reference` to the descriptor. Return
|
||||
``NULL`` with an exception set on failure.
|
||||
|
||||
.. c:var:: PyTypeObject PyMethodDescr_Type
|
||||
|
||||
The type object for method descriptor objects created from
|
||||
:c:type:`PyMethodDef` structures. These descriptors expose C functions as
|
||||
methods on a type, and correspond to :class:`types.MemberDescriptorType`
|
||||
methods on a type, and correspond to :class:`types.MethodDescriptorType`
|
||||
objects in Python.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *wrapper, void *wrapped)
|
||||
.. c:struct:: wrapperbase
|
||||
|
||||
Describes a slot wrapper used by :c:func:`PyDescr_NewWrapper`.
|
||||
|
||||
Each ``wrapperbase`` record stores the Python-visible name and metadata for a
|
||||
special method implemented by a type slot, together with the wrapper
|
||||
function used to adapt that slot to Python's calling convention.
|
||||
|
||||
.. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
|
||||
|
||||
Create a new wrapper descriptor for extension type *type* from the
|
||||
:c:struct:`wrapperbase` structure *base* and the wrapped slot function
|
||||
pointer
|
||||
*wrapped*.
|
||||
|
||||
Wrapper descriptors expose special methods implemented by type slots. This
|
||||
is the same kind of descriptor that CPython creates for slot-based special
|
||||
methods such as ``__repr__`` or ``__add__``, and it appears in Python as a
|
||||
:class:`types.WrapperDescriptorType` object.
|
||||
|
||||
On success, return a :term:`strong reference` to the descriptor. Return
|
||||
``NULL`` with an exception set on failure.
|
||||
|
||||
.. c:var:: PyTypeObject PyWrapperDescr_Type
|
||||
|
||||
|
|
@ -58,6 +107,16 @@ found in the dictionary of type objects.
|
|||
|
||||
.. c:function:: PyObject* PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)
|
||||
|
||||
Create a new class method descriptor for extension type *type* from the
|
||||
:c:type:`PyMethodDef` structure *method*.
|
||||
|
||||
Class method descriptors expose C methods that receive the class rather than
|
||||
an instance when accessed. This is the same kind of descriptor created for
|
||||
``METH_CLASS`` entries in :c:member:`~PyTypeObject.tp_methods`, and it
|
||||
appears in Python as a :class:`types.ClassMethodDescriptorType` object.
|
||||
|
||||
On success, return a :term:`strong reference` to the descriptor. Return
|
||||
``NULL`` with an exception set on failure.
|
||||
|
||||
.. c:function:: int PyDescr_IsData(PyObject *descr)
|
||||
|
||||
|
|
@ -66,12 +125,22 @@ found in the dictionary of type objects.
|
|||
no error checking.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyWrapper_New(PyObject *, PyObject *)
|
||||
.. c:function:: PyObject* PyWrapper_New(PyObject *d, PyObject *self)
|
||||
|
||||
Create a new bound wrapper object from the wrapper descriptor *d* and the
|
||||
instance *self*.
|
||||
|
||||
This is the bound form of a wrapper descriptor created by
|
||||
:c:func:`PyDescr_NewWrapper`. CPython creates these objects when a slot
|
||||
wrapper is accessed through an instance, and they appear in Python as
|
||||
:class:`types.MethodWrapperType` objects.
|
||||
|
||||
On success, return a :term:`strong reference` to the wrapper object. Return
|
||||
``NULL`` with an exception set on failure.
|
||||
|
||||
.. c:macro:: PyDescr_COMMON
|
||||
|
||||
This is a :term:`soft deprecated` macro including the common fields for a
|
||||
This is a macro including the common fields for a
|
||||
descriptor object.
|
||||
|
||||
This was included in Python's C API by mistake; do not use it in extensions.
|
||||
|
|
@ -79,6 +148,8 @@ found in the dictionary of type objects.
|
|||
descriptor protocol (:c:member:`~PyTypeObject.tp_descr_get` and
|
||||
:c:member:`~PyTypeObject.tp_descr_set`).
|
||||
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
|
||||
Built-in descriptors
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -104,9 +175,9 @@ Built-in descriptors
|
|||
.. c:var:: PyTypeObject PyClassMethodDescr_Type
|
||||
|
||||
The type object for C-level class method descriptor objects.
|
||||
This is the type of the descriptors created for :func:`classmethod` defined in
|
||||
C extension types, and is the same object as :class:`classmethod`
|
||||
in Python.
|
||||
This is the type of the descriptors created for :func:`classmethod` defined
|
||||
in C extension types, and corresponds to
|
||||
:class:`types.ClassMethodDescriptorType` objects in Python.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyClassMethod_New(PyObject *callable)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
.. _dictobjects:
|
||||
|
||||
Dictionary Objects
|
||||
Dictionary objects
|
||||
------------------
|
||||
|
||||
.. index:: pair: object; dictionary
|
||||
|
|
@ -42,6 +42,12 @@ Dictionary Objects
|
|||
enforces read-only behavior. This is normally used to create a view to
|
||||
prevent modification of the dictionary for non-dynamic class types.
|
||||
|
||||
The first argument can be a :class:`dict`, a :class:`frozendict`, or a
|
||||
mapping.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyDictProxy_Type
|
||||
|
||||
|
|
@ -58,6 +64,9 @@ Dictionary Objects
|
|||
|
||||
Empty an existing dictionary of all key-value pairs.
|
||||
|
||||
Do nothing if the argument is not a :class:`dict` or a :class:`!dict`
|
||||
subclass.
|
||||
|
||||
|
||||
.. c:function:: int PyDict_Contains(PyObject *p, PyObject *key)
|
||||
|
||||
|
|
@ -65,6 +74,16 @@ Dictionary Objects
|
|||
*key*, return ``1``, otherwise return ``0``. On error, return ``-1``.
|
||||
This is equivalent to the Python expression ``key in p``.
|
||||
|
||||
The first argument can be a :class:`dict` or a :class:`frozendict`.
|
||||
|
||||
.. note::
|
||||
|
||||
The operation is atomic on :term:`free threading <free-threaded build>`
|
||||
when *key* is :class:`str`, :class:`int`, :class:`float`, :class:`bool` or :class:`bytes`.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
|
||||
.. c:function:: int PyDict_ContainsString(PyObject *p, const char *key)
|
||||
|
||||
|
|
@ -72,14 +91,18 @@ Dictionary Objects
|
|||
:c:expr:`const char*` UTF-8 encoded bytes string, rather than a
|
||||
:c:expr:`PyObject*`.
|
||||
|
||||
The first argument can be a :class:`dict` or a :class:`frozendict`.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDict_Copy(PyObject *p)
|
||||
|
||||
Return a new dictionary that contains the same key-value pairs as *p*.
|
||||
|
||||
|
||||
.. c:function:: int PyDict_SetItem(PyObject *p, PyObject *key, PyObject *val)
|
||||
|
||||
Insert *val* into the dictionary *p* with a key of *key*. *key* must be
|
||||
|
|
@ -87,6 +110,11 @@ Dictionary Objects
|
|||
``0`` on success or ``-1`` on failure. This function *does not* steal a
|
||||
reference to *val*.
|
||||
|
||||
.. note::
|
||||
|
||||
The operation is atomic on :term:`free threading <free-threaded build>`
|
||||
when *key* is :class:`str`, :class:`int`, :class:`float`, :class:`bool` or :class:`bytes`.
|
||||
|
||||
|
||||
.. c:function:: int PyDict_SetItemString(PyObject *p, const char *key, PyObject *val)
|
||||
|
||||
|
|
@ -102,6 +130,11 @@ Dictionary Objects
|
|||
If *key* is not in the dictionary, :exc:`KeyError` is raised.
|
||||
Return ``0`` on success or ``-1`` on failure.
|
||||
|
||||
.. note::
|
||||
|
||||
The operation is atomic on :term:`free threading <free-threaded build>`
|
||||
when *key* is :class:`str`, :class:`int`, :class:`float`, :class:`bool` or :class:`bytes`.
|
||||
|
||||
|
||||
.. c:function:: int PyDict_DelItemString(PyObject *p, const char *key)
|
||||
|
||||
|
|
@ -120,8 +153,18 @@ Dictionary Objects
|
|||
* If the key is missing, set *\*result* to ``NULL`` and return ``0``.
|
||||
* On error, raise an exception and return ``-1``.
|
||||
|
||||
The first argument can be a :class:`dict` or a :class:`frozendict`.
|
||||
|
||||
.. note::
|
||||
|
||||
The operation is atomic on :term:`free threading <free-threaded build>`
|
||||
when *key* is :class:`str`, :class:`int`, :class:`float`, :class:`bool` or :class:`bytes`.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
See also the :c:func:`PyObject_GetItem` function.
|
||||
|
||||
|
||||
|
|
@ -131,16 +174,28 @@ Dictionary Objects
|
|||
has a key *key*. Return ``NULL`` if the key *key* is missing *without*
|
||||
setting an exception.
|
||||
|
||||
The first argument can be a :class:`dict` or a :class:`frozendict`.
|
||||
|
||||
.. note::
|
||||
|
||||
Exceptions that occur while this calls :meth:`~object.__hash__` and
|
||||
:meth:`~object.__eq__` methods are silently ignored.
|
||||
Prefer the :c:func:`PyDict_GetItemWithError` function instead.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, the returned
|
||||
:term:`borrowed reference` may become invalid if another thread modifies
|
||||
the dictionary concurrently. Prefer :c:func:`PyDict_GetItemRef`, which
|
||||
returns a :term:`strong reference`.
|
||||
|
||||
.. versionchanged:: 3.10
|
||||
Calling this API without an :term:`attached thread state` had been allowed for historical
|
||||
reason. It is no longer allowed.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDict_GetItemWithError(PyObject *p, PyObject *key)
|
||||
|
||||
|
|
@ -149,6 +204,16 @@ Dictionary Objects
|
|||
occurred. Return ``NULL`` **without** an exception set if the key
|
||||
wasn't present.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, the returned
|
||||
:term:`borrowed reference` may become invalid if another thread modifies
|
||||
the dictionary concurrently. Prefer :c:func:`PyDict_GetItemRef`, which
|
||||
returns a :term:`strong reference`.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDict_GetItemString(PyObject *p, const char *key)
|
||||
|
||||
|
|
@ -164,6 +229,16 @@ Dictionary Objects
|
|||
Prefer using the :c:func:`PyDict_GetItemWithError` function with your own
|
||||
:c:func:`PyUnicode_FromString` *key* instead.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, the returned
|
||||
:term:`borrowed reference` may become invalid if another thread modifies
|
||||
the dictionary concurrently. Prefer :c:func:`PyDict_GetItemStringRef`,
|
||||
which returns a :term:`strong reference`.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
|
||||
.. c:function:: int PyDict_GetItemStringRef(PyObject *p, const char *key, PyObject **result)
|
||||
|
||||
|
|
@ -173,6 +248,9 @@ Dictionary Objects
|
|||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDict_SetDefault(PyObject *p, PyObject *key, PyObject *defaultobj)
|
||||
|
||||
|
|
@ -184,6 +262,14 @@ Dictionary Objects
|
|||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, the returned
|
||||
:term:`borrowed reference` may become invalid if another thread modifies
|
||||
the dictionary concurrently. Prefer :c:func:`PyDict_SetDefaultRef`,
|
||||
which returns a :term:`strong reference`.
|
||||
|
||||
|
||||
|
||||
.. c:function:: int PyDict_SetDefaultRef(PyObject *p, PyObject *key, PyObject *default_value, PyObject **result)
|
||||
|
||||
|
|
@ -203,6 +289,11 @@ Dictionary Objects
|
|||
These may refer to the same object: in that case you hold two separate
|
||||
references to it.
|
||||
|
||||
.. note::
|
||||
|
||||
The operation is atomic on :term:`free threading <free-threaded build>`
|
||||
when *key* is :class:`str`, :class:`int`, :class:`float`, :class:`bool` or :class:`bytes`.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
|
|
@ -220,6 +311,11 @@ Dictionary Objects
|
|||
Similar to :meth:`dict.pop`, but without the default value and
|
||||
not raising :exc:`KeyError` if the key is missing.
|
||||
|
||||
.. note::
|
||||
|
||||
The operation is atomic on :term:`free threading <free-threaded build>`
|
||||
when *key* is :class:`str`, :class:`int`, :class:`float`, :class:`bool` or :class:`bytes`.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
|
|
@ -236,17 +332,32 @@ Dictionary Objects
|
|||
|
||||
Return a :c:type:`PyListObject` containing all the items from the dictionary.
|
||||
|
||||
The first argument can be a :class:`dict` or a :class:`frozendict`.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDict_Keys(PyObject *p)
|
||||
|
||||
Return a :c:type:`PyListObject` containing all the keys from the dictionary.
|
||||
|
||||
The first argument can be a :class:`dict` or a :class:`frozendict`.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDict_Values(PyObject *p)
|
||||
|
||||
Return a :c:type:`PyListObject` containing all the values from the dictionary
|
||||
*p*.
|
||||
|
||||
The first argument can be a :class:`dict` or a :class:`frozendict`.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
|
||||
.. c:function:: Py_ssize_t PyDict_Size(PyObject *p)
|
||||
|
||||
|
|
@ -255,11 +366,19 @@ Dictionary Objects
|
|||
Return the number of items in the dictionary. This is equivalent to
|
||||
``len(p)`` on a dictionary.
|
||||
|
||||
The argument can be a :class:`dict` or a :class:`frozendict`.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
|
||||
.. c:function:: Py_ssize_t PyDict_GET_SIZE(PyObject *p)
|
||||
|
||||
Similar to :c:func:`PyDict_Size`, but without error checking.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
|
||||
.. c:function:: int PyDict_Next(PyObject *p, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue)
|
||||
|
||||
|
|
@ -274,6 +393,8 @@ Dictionary Objects
|
|||
value represents offsets within the internal dictionary structure, and
|
||||
since the structure is sparse, the offsets are not consecutive.
|
||||
|
||||
The first argument can be a :class:`dict` or a :class:`frozendict`.
|
||||
|
||||
For example::
|
||||
|
||||
PyObject *key, *value;
|
||||
|
|
@ -307,7 +428,7 @@ Dictionary Objects
|
|||
}
|
||||
|
||||
The function is not thread-safe in the :term:`free-threaded <free threading>`
|
||||
build without external synchronization. You can use
|
||||
build without external synchronization for a mutable :class:`dict`. You can use
|
||||
:c:macro:`Py_BEGIN_CRITICAL_SECTION` to lock the dictionary while iterating
|
||||
over it::
|
||||
|
||||
|
|
@ -317,6 +438,8 @@ Dictionary Objects
|
|||
}
|
||||
Py_END_CRITICAL_SECTION();
|
||||
|
||||
The function is thread-safe on a :class:`frozendict`.
|
||||
|
||||
.. note::
|
||||
|
||||
On the free-threaded build, this function can be used safely inside a
|
||||
|
|
@ -327,6 +450,9 @@ Dictionary Objects
|
|||
:term:`strong reference <strong reference>` (for example, using
|
||||
:c:func:`Py_NewRef`).
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Also accept :class:`frozendict`.
|
||||
|
||||
.. c:function:: int PyDict_Merge(PyObject *a, PyObject *b, int override)
|
||||
|
||||
Iterate over mapping object *b* adding key-value pairs to dictionary *a*.
|
||||
|
|
@ -336,6 +462,13 @@ Dictionary Objects
|
|||
only be added if there is not a matching key in *a*. Return ``0`` on
|
||||
success or ``-1`` if an exception was raised.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, when *b* is a
|
||||
:class:`dict` (with the standard iterator), both *a* and *b* are locked
|
||||
for the duration of the operation. When *b* is a non-dict mapping, only
|
||||
*a* is locked; *b* may be concurrently modified by another thread.
|
||||
|
||||
|
||||
.. c:function:: int PyDict_Update(PyObject *a, PyObject *b)
|
||||
|
||||
|
|
@ -345,6 +478,13 @@ Dictionary Objects
|
|||
argument has no "keys" attribute. Return ``0`` on success or ``-1`` if an
|
||||
exception was raised.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, when *b* is a
|
||||
:class:`dict` (with the standard iterator), both *a* and *b* are locked
|
||||
for the duration of the operation. When *b* is a non-dict mapping, only
|
||||
*a* is locked; *b* may be concurrently modified by another thread.
|
||||
|
||||
|
||||
.. c:function:: int PyDict_MergeFromSeq2(PyObject *a, PyObject *seq2, int override)
|
||||
|
||||
|
|
@ -360,6 +500,13 @@ Dictionary Objects
|
|||
if override or key not in a:
|
||||
a[key] = value
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded <free threading>` build, only *a* is locked.
|
||||
The iteration over *seq2* is not synchronized; *seq2* may be concurrently
|
||||
modified by another thread.
|
||||
|
||||
|
||||
.. c:function:: int PyDict_AddWatcher(PyDict_WatchCallback callback)
|
||||
|
||||
Register *callback* as a dictionary watcher. Return a non-negative integer
|
||||
|
|
@ -367,6 +514,13 @@ Dictionary Objects
|
|||
of error (e.g. no more watcher IDs available), return ``-1`` and set an
|
||||
exception.
|
||||
|
||||
.. note::
|
||||
|
||||
This function is not internally synchronized. In the
|
||||
:term:`free-threaded <free threading>` build, callers should ensure no
|
||||
concurrent calls to :c:func:`PyDict_AddWatcher` or
|
||||
:c:func:`PyDict_ClearWatcher` are in progress.
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
.. c:function:: int PyDict_ClearWatcher(int watcher_id)
|
||||
|
|
@ -375,6 +529,13 @@ Dictionary Objects
|
|||
:c:func:`PyDict_AddWatcher`. Return ``0`` on success, ``-1`` on error (e.g.
|
||||
if the given *watcher_id* was never registered.)
|
||||
|
||||
.. note::
|
||||
|
||||
This function is not internally synchronized. In the
|
||||
:term:`free-threaded <free threading>` build, callers should ensure no
|
||||
concurrent calls to :c:func:`PyDict_AddWatcher` or
|
||||
:c:func:`PyDict_ClearWatcher` are in progress.
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
.. c:function:: int PyDict_Watch(int watcher_id, PyObject *dict)
|
||||
|
|
@ -444,7 +605,7 @@ Dictionary Objects
|
|||
.. versionadded:: 3.12
|
||||
|
||||
|
||||
Dictionary View Objects
|
||||
Dictionary view objects
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. c:function:: int PyDictViewSet_Check(PyObject *op)
|
||||
|
|
@ -490,7 +651,58 @@ Dictionary View Objects
|
|||
always succeeds.
|
||||
|
||||
|
||||
Ordered Dictionaries
|
||||
Frozen dictionary objects
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyFrozenDict_Type
|
||||
|
||||
This instance of :c:type:`PyTypeObject` represents the Python frozen
|
||||
dictionary type.
|
||||
This is the same object as :class:`frozendict` in the Python layer.
|
||||
|
||||
|
||||
.. c:function:: int PyAnyDict_Check(PyObject *p)
|
||||
|
||||
Return true if *p* is a :class:`dict` object, a :class:`frozendict` object,
|
||||
or an instance of a subtype of the :class:`!dict` or :class:`!frozendict`
|
||||
type.
|
||||
This function always succeeds.
|
||||
|
||||
|
||||
.. c:function:: int PyAnyDict_CheckExact(PyObject *p)
|
||||
|
||||
Return true if *p* is a :class:`dict` object or a :class:`frozendict` object,
|
||||
but not an instance of a subtype of the :class:`!dict` or
|
||||
:class:`!frozendict` type.
|
||||
This function always succeeds.
|
||||
|
||||
|
||||
.. c:function:: int PyFrozenDict_Check(PyObject *p)
|
||||
|
||||
Return true if *p* is a :class:`frozendict` object or an instance of a
|
||||
subtype of the :class:`!frozendict` type.
|
||||
This function always succeeds.
|
||||
|
||||
|
||||
.. c:function:: int PyFrozenDict_CheckExact(PyObject *p)
|
||||
|
||||
Return true if *p* is a :class:`frozendict` object, but not an instance of a
|
||||
subtype of the :class:`!frozendict` type.
|
||||
This function always succeeds.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyFrozenDict_New(PyObject *iterable)
|
||||
|
||||
Return a new :class:`frozendict` from an iterable, or ``NULL`` on failure
|
||||
with an exception set.
|
||||
|
||||
Create an empty dictionary if *iterable* is ``NULL``.
|
||||
|
||||
|
||||
Ordered dictionaries
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Python's C API provides interface for :class:`collections.OrderedDict` from C.
|
||||
|
|
|
|||
|
|
@ -673,28 +673,51 @@ Signal Handling
|
|||
single: SIGINT (C macro)
|
||||
single: KeyboardInterrupt (built-in exception)
|
||||
|
||||
This function interacts with Python's signal handling.
|
||||
Handle external interruptions, such as signals or activating a debugger,
|
||||
whose processing has been delayed until it is safe
|
||||
to run Python code and/or raise exceptions.
|
||||
|
||||
If the function is called from the main thread and under the main Python
|
||||
interpreter, it checks whether a signal has been sent to the processes
|
||||
and if so, invokes the corresponding signal handler. If the :mod:`signal`
|
||||
module is supported, this can invoke a signal handler written in Python.
|
||||
For example, pressing :kbd:`Ctrl-C` causes a terminal to send the
|
||||
:py:data:`signal.SIGINT` signal.
|
||||
This function executes the corresponding Python signal handler, which,
|
||||
by default, raises the :exc:`KeyboardInterrupt` exception.
|
||||
|
||||
The function attempts to handle all pending signals, and then returns ``0``.
|
||||
However, if a Python signal handler raises an exception, the error
|
||||
indicator is set and the function returns ``-1`` immediately (such that
|
||||
other pending signals may not have been handled yet: they will be on the
|
||||
next :c:func:`PyErr_CheckSignals()` invocation).
|
||||
:c:func:`!PyErr_CheckSignals` should be called by long-running C code
|
||||
frequently enough so that the response appears immediate to humans.
|
||||
|
||||
If the function is called from a non-main thread, or under a non-main
|
||||
Python interpreter, it does nothing and returns ``0``.
|
||||
Handlers invoked by this function currently include:
|
||||
|
||||
This function can be called by long-running C code that wants to
|
||||
be interruptible by user requests (such as by pressing Ctrl-C).
|
||||
- Signal handlers, including Python functions registered using
|
||||
the :mod:`signal` module.
|
||||
|
||||
.. note::
|
||||
The default Python signal handler for :c:macro:`!SIGINT` raises the
|
||||
:exc:`KeyboardInterrupt` exception.
|
||||
Signal handlers are only run in the main thread of the main interpreter.
|
||||
|
||||
(This is where the function got the name: originally, signals
|
||||
were the only way to interrupt the interpreter.)
|
||||
|
||||
- Running the garbage collector, if necessary.
|
||||
|
||||
- Executing a pending :ref:`remote debugger <remote-debugging>` script.
|
||||
|
||||
- Raise the exception set by :c:func:`PyThreadState_SetAsyncExc`.
|
||||
|
||||
If any handler raises an exception, immediately return ``-1`` with that
|
||||
exception set.
|
||||
Any remaining interruptions are left to be processed on the next
|
||||
:c:func:`PyErr_CheckSignals()` invocation, if appropriate.
|
||||
|
||||
If all handlers finish successfully, or there are no handlers to run,
|
||||
return ``0``.
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
This function may now invoke the garbage collector.
|
||||
|
||||
.. versionchanged:: 3.14
|
||||
This function may now execute a remote debugger script, if remote
|
||||
debugging is enabled.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
The exception set by :c:func:`PyThreadState_SetAsyncExc` is now raised.
|
||||
|
||||
|
||||
.. c:function:: void PyErr_SetInterrupt()
|
||||
|
|
@ -795,7 +818,7 @@ Exception Classes
|
|||
|
||||
.. c:macro:: PyException_HEAD
|
||||
|
||||
This is a :term:`soft deprecated` macro including the base fields for an
|
||||
This is a macro including the base fields for an
|
||||
exception object.
|
||||
|
||||
This was included in Python's C API by mistake and is not designed for use
|
||||
|
|
@ -803,6 +826,8 @@ Exception Classes
|
|||
:c:func:`PyErr_NewException` or otherwise create a class inheriting from
|
||||
:c:data:`PyExc_BaseException`.
|
||||
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
|
||||
Exception Objects
|
||||
=================
|
||||
|
|
@ -1119,6 +1144,8 @@ Exception types
|
|||
* :exc:`FloatingPointError`
|
||||
* * .. c:var:: PyObject *PyExc_GeneratorExit
|
||||
* :exc:`GeneratorExit`
|
||||
* * .. c:var:: PyObject *PyExc_ImportCycleError
|
||||
* :exc:`ImportCycleError`
|
||||
* * .. c:var:: PyObject *PyExc_ImportError
|
||||
* :exc:`ImportError`
|
||||
* * .. c:var:: PyObject *PyExc_IndentationError
|
||||
|
|
|
|||
|
|
@ -191,10 +191,10 @@ the :c:data:`Py_mod_multiple_interpreters` slot.
|
|||
``PyInit`` function
|
||||
...................
|
||||
|
||||
.. deprecated:: 3.15
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
This functionality is :term:`soft deprecated`.
|
||||
It will not get new features, but there are no plans to remove it.
|
||||
This functionality will not get new features,
|
||||
but there are no plans to remove it.
|
||||
|
||||
Instead of :c:func:`PyModExport_modulename`, an extension module can define
|
||||
an older-style :dfn:`initialization function` with the signature:
|
||||
|
|
@ -272,10 +272,9 @@ For example, a module called ``spam`` would be defined like this::
|
|||
Legacy single-phase initialization
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. deprecated:: 3.15
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
Single-phase initialization is :term:`soft deprecated`.
|
||||
It is a legacy mechanism to initialize extension
|
||||
Single-phase initialization is a legacy mechanism to initialize extension
|
||||
modules, with known drawbacks and design flaws. Extension module authors
|
||||
are encouraged to use multi-phase initialization instead.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
.. _fileobjects:
|
||||
|
||||
File Objects
|
||||
File objects
|
||||
------------
|
||||
|
||||
.. index:: pair: object; file
|
||||
|
|
@ -123,9 +123,12 @@ the :mod:`io` APIs instead.
|
|||
|
||||
Write object *obj* to file object *p*. The only supported flag for *flags* is
|
||||
:c:macro:`Py_PRINT_RAW`; if given, the :func:`str` of the object is written
|
||||
instead of the :func:`repr`. Return ``0`` on success or ``-1`` on failure; the
|
||||
appropriate exception will be set.
|
||||
instead of the :func:`repr`.
|
||||
|
||||
If *obj* is ``NULL``, write the string ``"<NULL>"``.
|
||||
|
||||
Return ``0`` on success or ``-1`` on failure; the
|
||||
appropriate exception will be set.
|
||||
|
||||
.. c:function:: int PyFile_WriteString(const char *s, PyObject *p)
|
||||
|
||||
|
|
@ -133,11 +136,12 @@ the :mod:`io` APIs instead.
|
|||
failure; the appropriate exception will be set.
|
||||
|
||||
|
||||
Deprecated API
|
||||
^^^^^^^^^^^^^^
|
||||
Soft-deprecated API
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
These are :term:`soft deprecated` APIs that were included in Python's C API
|
||||
These are APIs that were included in Python's C API
|
||||
by mistake. They are documented solely for completeness; use other
|
||||
``PyFile*`` APIs instead.
|
||||
|
||||
|
|
|
|||
|
|
@ -80,19 +80,18 @@ Floating-Point Objects
|
|||
|
||||
.. c:macro:: Py_INFINITY
|
||||
|
||||
This macro expands a to constant expression of type :c:expr:`double`, that
|
||||
This macro expands to a constant expression of type :c:expr:`double`, that
|
||||
represents the positive infinity.
|
||||
|
||||
It is equivalent to the :c:macro:`!INFINITY` macro from the C11 standard
|
||||
``<math.h>`` header.
|
||||
|
||||
.. deprecated:: 3.15
|
||||
The macro is :term:`soft deprecated`.
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
|
||||
.. c:macro:: Py_NAN
|
||||
|
||||
This macro expands a to constant expression of type :c:expr:`double`, that
|
||||
This macro expands to a constant expression of type :c:expr:`double`, that
|
||||
represents a quiet not-a-number (qNaN) value.
|
||||
|
||||
On most platforms, this is equivalent to the :c:macro:`!NAN` macro from
|
||||
|
|
@ -103,8 +102,7 @@ Floating-Point Objects
|
|||
|
||||
Equivalent to :c:macro:`!INFINITY`.
|
||||
|
||||
.. deprecated:: 3.14
|
||||
The macro is :term:`soft deprecated`.
|
||||
.. soft-deprecated:: 3.14
|
||||
|
||||
|
||||
.. c:macro:: Py_MATH_E
|
||||
|
|
@ -161,8 +159,8 @@ Floating-Point Objects
|
|||
that is, it is normal, subnormal or zero, but not infinite or NaN.
|
||||
Return ``0`` otherwise.
|
||||
|
||||
.. deprecated:: 3.14
|
||||
The macro is :term:`soft deprecated`. Use :c:macro:`!isfinite` instead.
|
||||
.. soft-deprecated:: 3.14
|
||||
Use :c:macro:`!isfinite` instead.
|
||||
|
||||
|
||||
.. c:macro:: Py_IS_INFINITY(X)
|
||||
|
|
@ -170,8 +168,8 @@ Floating-Point Objects
|
|||
Return ``1`` if the given floating-point number *X* is positive or negative
|
||||
infinity. Return ``0`` otherwise.
|
||||
|
||||
.. deprecated:: 3.14
|
||||
The macro is :term:`soft deprecated`. Use :c:macro:`!isinf` instead.
|
||||
.. soft-deprecated:: 3.14
|
||||
Use :c:macro:`!isinf` instead.
|
||||
|
||||
|
||||
.. c:macro:: Py_IS_NAN(X)
|
||||
|
|
@ -179,8 +177,8 @@ Floating-Point Objects
|
|||
Return ``1`` if the given floating-point number *X* is a not-a-number (NaN)
|
||||
value. Return ``0`` otherwise.
|
||||
|
||||
.. deprecated:: 3.14
|
||||
The macro is :term:`soft deprecated`. Use :c:macro:`!isnan` instead.
|
||||
.. soft-deprecated:: 3.14
|
||||
Use :c:macro:`!isnan` instead.
|
||||
|
||||
|
||||
Pack and Unpack functions
|
||||
|
|
@ -190,24 +188,23 @@ The pack and unpack functions provide an efficient platform-independent way to
|
|||
store floating-point values as byte strings. The Pack routines produce a bytes
|
||||
string from a C :c:expr:`double`, and the Unpack routines produce a C
|
||||
:c:expr:`double` from such a bytes string. The suffix (2, 4 or 8) specifies the
|
||||
number of bytes in the bytes string.
|
||||
number of bytes in the bytes string:
|
||||
|
||||
On platforms that appear to use IEEE 754 formats these functions work by
|
||||
copying bits. On other platforms, the 2-byte format is identical to the IEEE
|
||||
754 binary16 half-precision format, the 4-byte format (32-bit) is identical to
|
||||
the IEEE 754 binary32 single precision format, and the 8-byte format to the
|
||||
IEEE 754 binary64 double precision format, although the packing of INFs and
|
||||
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.
|
||||
* The 2-byte format is the IEEE 754 binary16 half-precision format.
|
||||
* The 4-byte format is the IEEE 754 binary32 single-precision format.
|
||||
* The 8-byte format is the IEEE 754 binary64 double-precision format.
|
||||
|
||||
Note that NaNs type may not be preserved on IEEE platforms (signaling NaN become
|
||||
quiet NaN), for example on x86 systems in 32-bit mode.
|
||||
The NaN type may not be preserved on some platforms while unpacking (signaling
|
||||
NaNs become quiet NaNs), for example on x86 systems in 32-bit mode.
|
||||
|
||||
It's assumed that the :c:expr:`double` type has the IEEE 754 binary64 double
|
||||
precision format. What happens if it's not true is partly accidental (alas).
|
||||
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
|
||||
happens in such cases is partly accidental (alas).
|
||||
precision, or smaller dynamic range, not all values can be unpacked. The
|
||||
packing of special numbers like INFs and NaNs (if such things exist on the
|
||||
platform) may not be handled correctly, and attempting to unpack a bytes string
|
||||
containing an IEEE INF or NaN may raise an exception.
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
|
|
@ -216,19 +213,14 @@ Pack functions
|
|||
|
||||
The pack routines write 2, 4 or 8 bytes, starting at *p*. *le* is an
|
||||
:c:expr:`int` argument, non-zero if you want the bytes string in little-endian
|
||||
format (exponent last, at ``p+1``, ``p+3``, or ``p+6`` ``p+7``), zero if you
|
||||
want big-endian format (exponent first, at *p*). The :c:macro:`PY_BIG_ENDIAN`
|
||||
constant can be used to use the native endian: it is equal to ``1`` on big
|
||||
endian processor, or ``0`` on little endian processor.
|
||||
format (exponent last, at ``p+1``, ``p+3``, or ``p+6`` and ``p+7``), zero if you
|
||||
want big-endian format (exponent first, at *p*). Use the :c:macro:`!PY_LITTLE_ENDIAN`
|
||||
constant to select the native endian: it is equal to ``0`` on big
|
||||
endian processor, or ``1`` on little endian processor.
|
||||
|
||||
Return value: ``0`` if all is OK, ``-1`` if error (and an exception is set,
|
||||
most likely :exc:`OverflowError`).
|
||||
|
||||
There are two problems on non-IEEE platforms:
|
||||
|
||||
* What this does is undefined if *x* is a NaN or infinity.
|
||||
* ``-0.0`` and ``+0.0`` produce the same bytes string.
|
||||
|
||||
.. c:function:: int PyFloat_Pack2(double x, char *p, int le)
|
||||
|
||||
Pack a C double as the IEEE 754 binary16 half-precision format.
|
||||
|
|
@ -241,6 +233,9 @@ There are two problems on non-IEEE platforms:
|
|||
|
||||
Pack a C double as the IEEE 754 binary64 double precision format.
|
||||
|
||||
.. impl-detail::
|
||||
This function always succeeds in CPython.
|
||||
|
||||
|
||||
Unpack functions
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
|
@ -248,16 +243,16 @@ Unpack functions
|
|||
The unpack routines read 2, 4 or 8 bytes, starting at *p*. *le* is an
|
||||
:c:expr:`int` argument, non-zero if the bytes string is in little-endian format
|
||||
(exponent last, at ``p+1``, ``p+3`` or ``p+6`` and ``p+7``), zero if big-endian
|
||||
(exponent first, at *p*). The :c:macro:`PY_BIG_ENDIAN` constant can be used to
|
||||
use the native endian: it is equal to ``1`` on big endian processor, or ``0``
|
||||
(exponent first, at *p*). Use the :c:macro:`!PY_LITTLE_ENDIAN` constant to
|
||||
select the native endian: it is equal to ``0`` on big endian processor, or ``1``
|
||||
on little endian processor.
|
||||
|
||||
Return value: The unpacked double. On error, this is ``-1.0`` and
|
||||
:c:func:`PyErr_Occurred` is true (and an exception is set, most likely
|
||||
:exc:`OverflowError`).
|
||||
|
||||
Note that on a non-IEEE platform this will refuse to unpack a bytes string that
|
||||
represents a NaN or infinity.
|
||||
.. impl-detail::
|
||||
These functions always succeed in CPython.
|
||||
|
||||
.. c:function:: double PyFloat_Unpack2(const char *p, int le)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
.. highlight:: c
|
||||
|
||||
Frame Objects
|
||||
Frame objects
|
||||
-------------
|
||||
|
||||
.. c:type:: PyFrameObject
|
||||
|
|
@ -50,6 +50,7 @@ See also :ref:`Reflection <reflection>`.
|
|||
|
||||
Return a :term:`strong reference`, or ``NULL`` if *frame* has no outer
|
||||
frame.
|
||||
This raises no exceptions.
|
||||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
|
|
@ -146,7 +147,7 @@ See also :ref:`Reflection <reflection>`.
|
|||
Return the line number that *frame* is currently executing.
|
||||
|
||||
|
||||
Frame Locals Proxies
|
||||
Frame locals proxies
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
|
@ -168,7 +169,7 @@ See :pep:`667` for more information.
|
|||
Return non-zero if *obj* is a frame :func:`locals` proxy.
|
||||
|
||||
|
||||
Legacy Local Variable APIs
|
||||
Legacy local variable APIs
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
These APIs are :term:`soft deprecated`. As of Python 3.13, they do nothing.
|
||||
|
|
@ -177,40 +178,34 @@ They exist solely for backwards compatibility.
|
|||
|
||||
.. c:function:: void PyFrame_LocalsToFast(PyFrameObject *f, int clear)
|
||||
|
||||
This function is :term:`soft deprecated` and does nothing.
|
||||
|
||||
Prior to Python 3.13, this function would copy the :attr:`~frame.f_locals`
|
||||
attribute of *f* to the internal "fast" array of local variables, allowing
|
||||
changes in frame objects to be visible to the interpreter. If *clear* was
|
||||
true, this function would process variables that were unset in the locals
|
||||
dictionary.
|
||||
|
||||
.. versionchanged:: 3.13
|
||||
.. soft-deprecated:: 3.13
|
||||
This function now does nothing.
|
||||
|
||||
|
||||
.. c:function:: void PyFrame_FastToLocals(PyFrameObject *f)
|
||||
|
||||
This function is :term:`soft deprecated` and does nothing.
|
||||
|
||||
Prior to Python 3.13, this function would copy the internal "fast" array
|
||||
of local variables (which is used by the interpreter) to the
|
||||
:attr:`~frame.f_locals` attribute of *f*, allowing changes in local
|
||||
variables to be visible to frame objects.
|
||||
|
||||
.. versionchanged:: 3.13
|
||||
.. soft-deprecated:: 3.13
|
||||
This function now does nothing.
|
||||
|
||||
|
||||
.. c:function:: int PyFrame_FastToLocalsWithError(PyFrameObject *f)
|
||||
|
||||
This function is :term:`soft deprecated` and does nothing.
|
||||
|
||||
Prior to Python 3.13, this function was similar to
|
||||
:c:func:`PyFrame_FastToLocals`, but would return ``0`` on success, and
|
||||
``-1`` with an exception set on failure.
|
||||
|
||||
.. versionchanged:: 3.13
|
||||
.. soft-deprecated:: 3.13
|
||||
This function now does nothing.
|
||||
|
||||
|
||||
|
|
@ -218,7 +213,7 @@ They exist solely for backwards compatibility.
|
|||
:pep:`667`
|
||||
|
||||
|
||||
Internal Frames
|
||||
Internal frames
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Unless using :pep:`523`, you will not need this.
|
||||
|
|
@ -248,5 +243,3 @@ Unless using :pep:`523`, you will not need this.
|
|||
Return the currently executing line number, or -1 if there is no line number.
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -220,42 +220,6 @@ The :c:member:`~PyTypeObject.tp_traverse` handler accepts a function parameter o
|
|||
detection; it's not expected that users will need to write their own
|
||||
visitor functions.
|
||||
|
||||
The :c:member:`~PyTypeObject.tp_traverse` handler must have the following type:
|
||||
|
||||
|
||||
.. c:type:: int (*traverseproc)(PyObject *self, visitproc visit, void *arg)
|
||||
|
||||
Traversal function for a container object. Implementations must call the
|
||||
*visit* function for each object directly contained by *self*, with the
|
||||
parameters to *visit* being the contained object and the *arg* value passed
|
||||
to the handler. The *visit* function must not be called with a ``NULL``
|
||||
object argument. If *visit* returns a non-zero value that value should be
|
||||
returned immediately.
|
||||
|
||||
The traversal function must not have any side effects. Implementations
|
||||
may not modify the reference counts of any Python objects nor create or
|
||||
destroy any Python objects.
|
||||
|
||||
To simplify writing :c:member:`~PyTypeObject.tp_traverse` handlers, a :c:func:`Py_VISIT` macro is
|
||||
provided. In order to use this macro, the :c:member:`~PyTypeObject.tp_traverse` implementation
|
||||
must name its arguments exactly *visit* and *arg*:
|
||||
|
||||
|
||||
.. c:macro:: Py_VISIT(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::
|
||||
|
||||
static int
|
||||
my_traverse(Noddy *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(self->foo);
|
||||
Py_VISIT(self->bar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
The :c:member:`~PyTypeObject.tp_clear` handler must be of the :c:type:`inquiry` type, or ``NULL``
|
||||
if the object is immutable.
|
||||
|
||||
|
|
@ -270,6 +234,225 @@ if the object is immutable.
|
|||
in a reference cycle.
|
||||
|
||||
|
||||
.. _gc-traversal:
|
||||
|
||||
Traversal
|
||||
---------
|
||||
|
||||
The :c:member:`~PyTypeObject.tp_traverse` handler must have the following type:
|
||||
|
||||
.. c:type:: int (*traverseproc)(PyObject *self, visitproc visit, void *arg)
|
||||
|
||||
Traversal function for a garbage-collected object, used by the garbage
|
||||
collector to detect reference cycles.
|
||||
Implementations must call the
|
||||
*visit* function for each object directly contained by *self*, with the
|
||||
parameters to *visit* being the contained object and the *arg* value passed
|
||||
to the handler. The *visit* function must not be called with a ``NULL``
|
||||
object argument. If *visit* returns a non-zero value, that value should be
|
||||
returned immediately.
|
||||
|
||||
A typical :c:member:`!tp_traverse` function calls the :c:func:`Py_VISIT`
|
||||
convenience macro on each of the instance's members that are Python
|
||||
objects that the instance owns.
|
||||
For example, this is a (slightly outdated) traversal function for
|
||||
the :py:class:`threading.local` class::
|
||||
|
||||
static int
|
||||
local_traverse(PyObject *op, visitproc visit, void *arg)
|
||||
{
|
||||
localobject *self = (localobject *) op;
|
||||
Py_VISIT(Py_TYPE(self));
|
||||
Py_VISIT(self->args);
|
||||
Py_VISIT(self->kw);
|
||||
Py_VISIT(self->dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
.. note::
|
||||
:c:func:`Py_VISIT` requires the *visit* and *arg* parameters to
|
||||
:c:func:`!local_traverse` to have these specific names; don't name them just
|
||||
anything.
|
||||
|
||||
Instances of :ref:`heap-allocated types <heap-types>` hold a reference to
|
||||
their type. Their traversal function must therefore visit the type::
|
||||
|
||||
Py_VISIT(Py_TYPE(self));
|
||||
|
||||
Alternately, the type may delegate this responsibility by
|
||||
calling ``tp_traverse`` of a heap-allocated superclass (or another
|
||||
heap-allocated type, if applicable).
|
||||
If they do not, the type object may not be garbage-collected.
|
||||
|
||||
If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the
|
||||
:c:member:`~PyTypeObject.tp_flags` field, the traverse function must call
|
||||
:c:func:`PyObject_VisitManagedDict` like this::
|
||||
|
||||
int err = PyObject_VisitManagedDict((PyObject*)self, visit, arg);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
Only the members that the instance *owns* (by having
|
||||
:term:`strong references <strong reference>` to them) must be
|
||||
visited. For instance, if an object supports weak references via the
|
||||
:c:member:`~PyTypeObject.tp_weaklist` slot, the pointer supporting
|
||||
the linked list (what *tp_weaklist* points to) must **not** be
|
||||
visited as the instance does not directly own the weak references to itself.
|
||||
|
||||
The traversal function has a limitation:
|
||||
|
||||
.. warning::
|
||||
|
||||
The traversal function must not have any side effects. Implementations
|
||||
may not modify the reference counts of any Python objects nor create or
|
||||
destroy any Python objects, directly or indirectly.
|
||||
|
||||
This means that *most* Python C API functions may not be used, since
|
||||
they can raise a new exception, return a new reference to a result object,
|
||||
have internal logic that uses side effects.
|
||||
Also, unless documented otherwise, functions that happen to not have side
|
||||
effects may start having them in future versions, without warning.
|
||||
|
||||
For a list of safe functions, see a
|
||||
:ref:`separate section <duringgc-functions>` below.
|
||||
|
||||
.. note::
|
||||
|
||||
The :c:func:`Py_VISIT` call may be skipped for those members that provably
|
||||
cannot participate in reference cycles.
|
||||
In the ``local_traverse`` example above, there is also a ``self->key``
|
||||
member, but it can only be ``NULL`` or a Python string and therefore
|
||||
cannot be part of a reference cycle.
|
||||
|
||||
On the other hand, even if you know a member can never be part of a cycle,
|
||||
as a debugging aid you may want to visit it anyway just so the :mod:`gc`
|
||||
module's :func:`~gc.get_referents` function will include it.
|
||||
|
||||
.. note::
|
||||
|
||||
The :c:member:`~PyTypeObject.tp_traverse` function can be called from any
|
||||
thread.
|
||||
|
||||
.. impl-detail::
|
||||
|
||||
Garbage collection is a "stop-the-world" operation:
|
||||
even in :term:`free threading` builds, only one thread state is
|
||||
:term:`attached <attached thread state>` when :c:member:`!tp_traverse`
|
||||
handlers run.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
|
||||
Heap-allocated types are expected to visit ``Py_TYPE(self)`` in
|
||||
``tp_traverse``. In earlier versions of Python, due to
|
||||
`bug 40217 <https://bugs.python.org/issue40217>`_, doing this
|
||||
may lead to crashes in subclasses.
|
||||
|
||||
To simplify writing :c:member:`~PyTypeObject.tp_traverse` handlers,
|
||||
a :c:func:`Py_VISIT` macro is provided.
|
||||
In order to use this macro, the :c:member:`~PyTypeObject.tp_traverse`
|
||||
implementation must name its arguments exactly *visit* and *arg*:
|
||||
|
||||
.. c:macro:: Py_VISIT(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.
|
||||
|
||||
This corresponds roughly to::
|
||||
|
||||
#define Py_VISIT(o) \
|
||||
if (op) { \
|
||||
int visit_result = visit(o, arg); \
|
||||
if (visit_result != 0) { \
|
||||
return visit_result; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
Traversal-safe functions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The following functions and macros are safe to use in a
|
||||
:c:member:`~PyTypeObject.tp_traverse` handler:
|
||||
|
||||
* the *visit* function passed to ``tp_traverse``
|
||||
* :c:func:`Py_VISIT`
|
||||
* :c:func:`Py_SIZE`
|
||||
* :c:func:`Py_TYPE`: if called from a :c:member:`!tp_traverse` handler,
|
||||
:c:func:`!Py_TYPE`'s result will be valid for the duration of the handler call
|
||||
* :c:func:`PyObject_VisitManagedDict`
|
||||
* :c:func:`PyObject_TypeCheck`, :c:func:`PyType_IsSubtype`,
|
||||
:c:func:`PyType_HasFeature`
|
||||
* :samp:`Py{<type>}_Check` and :samp:`Py{<type>}_CheckExact` -- for example,
|
||||
:c:func:`PyTuple_Check`
|
||||
* :ref:`duringgc-functions`
|
||||
|
||||
.. _duringgc-functions:
|
||||
|
||||
"DuringGC" functions
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The following functions should *only* be used in a
|
||||
:c:member:`~PyTypeObject.tp_traverse` handler; calling them in other
|
||||
contexts may have unintended consequences.
|
||||
|
||||
These functions act like their counterparts without the ``_DuringGC`` suffix,
|
||||
but they are guaranteed to not have side effects, they do not set an exception
|
||||
on failure, and they return/set :term:`borrowed references <borrowed reference>`
|
||||
as detailed in the individual documentation.
|
||||
|
||||
Note that these functions may fail (return ``NULL`` or ``-1``),
|
||||
but as they do not set an exception, no error information is available.
|
||||
In some cases, failure is not distinguishable from a successful ``NULL`` result.
|
||||
|
||||
.. c:function:: void *PyObject_GetTypeData_DuringGC(PyObject *o, PyTypeObject *cls)
|
||||
void *PyObject_GetItemData_DuringGC(PyObject *o)
|
||||
void *PyType_GetModuleState_DuringGC(PyTypeObject *type)
|
||||
void *PyModule_GetState_DuringGC(PyObject *module)
|
||||
int PyModule_GetToken_DuringGC(PyObject *module, void** result)
|
||||
|
||||
See :ref:`duringgc-functions` for common information.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
.. seealso::
|
||||
|
||||
:c:func:`PyObject_GetTypeData`,
|
||||
:c:func:`PyObject_GetItemData`,
|
||||
:c:func:`PyType_GetModuleState`,
|
||||
:c:func:`PyModule_GetState`,
|
||||
:c:func:`PyModule_GetToken`,
|
||||
:c:func:`PyType_GetBaseByToken`
|
||||
|
||||
.. c:function:: int PyType_GetBaseByToken_DuringGC(PyTypeObject *type, void *tp_token, PyTypeObject **result)
|
||||
|
||||
See :ref:`duringgc-functions` for common information.
|
||||
|
||||
Sets *\*result* to a :term:`borrowed reference` rather than a strong one.
|
||||
The reference is valid for the duration
|
||||
of the :c:member:`!tp_traverse` handler call.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
.. seealso:: :c:func:`PyType_GetBaseByToken`
|
||||
|
||||
.. c:function:: PyObject* PyType_GetModule_DuringGC(PyTypeObject *type)
|
||||
PyObject* PyType_GetModuleByToken_DuringGC(PyTypeObject *type, const void *mod_token)
|
||||
|
||||
See :ref:`duringgc-functions` for common information.
|
||||
|
||||
These functions return a :term:`borrowed reference`, which is
|
||||
valid for the duration of the :c:member:`!tp_traverse` handler call.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
.. seealso::
|
||||
|
||||
:c:func:`PyType_GetModule`,
|
||||
:c:func:`PyType_GetModuleByToken`
|
||||
|
||||
|
||||
Controlling the Garbage Collector State
|
||||
---------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,9 @@ Deprecated API
|
|||
|
||||
.. c:macro:: PyAsyncGenASend_CheckExact(op)
|
||||
|
||||
This is a :term:`soft deprecated` API that was included in Python's C API
|
||||
This is an API that was included in Python's C API
|
||||
by mistake.
|
||||
|
||||
It is solely here for completeness; do not use this API.
|
||||
|
||||
.. soft-deprecated:: 3.14
|
||||
|
|
|
|||
|
|
@ -346,6 +346,60 @@ Importing Modules
|
|||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
.. c:function:: PyImport_LazyImportsMode PyImport_GetLazyImportsMode()
|
||||
|
||||
Gets the current lazy imports mode.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
.. c:function:: PyObject* PyImport_GetLazyImportsFilter()
|
||||
|
||||
Return a :term:`strong reference` to the current lazy imports filter,
|
||||
or ``NULL`` if none exists. This function always succeeds.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
.. c:function:: int PyImport_SetLazyImportsMode(PyImport_LazyImportsMode mode)
|
||||
|
||||
Similar to :c:func:`PyImport_ImportModuleAttr`, but names are UTF-8 encoded
|
||||
strings instead of Python :class:`str` objects.
|
||||
|
||||
This function always returns ``0``.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
.. c:function:: int PyImport_SetLazyImportsFilter(PyObject *filter)
|
||||
|
||||
Sets the current lazy imports filter. The *filter* should be a callable that
|
||||
will receive ``(importing_module_name, imported_module_name, [fromlist])``
|
||||
when an import can potentially be lazy. The ``imported_module_name`` value
|
||||
is the resolved module name, so ``lazy from .spam import eggs`` passes
|
||||
``package.spam``. The callable must return ``True`` if the import should be
|
||||
lazy and ``False`` otherwise.
|
||||
|
||||
Return ``0`` on success and ``-1`` with an exception set otherwise.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
.. c:type:: PyImport_LazyImportsMode
|
||||
|
||||
Enumeration of possible lazy import modes.
|
||||
|
||||
.. c:enumerator:: PyImport_LAZY_NORMAL
|
||||
|
||||
Respect the ``lazy`` keyword in source code. This is the default mode.
|
||||
|
||||
.. c:enumerator:: PyImport_LAZY_ALL
|
||||
|
||||
Make all imports lazy by default.
|
||||
|
||||
.. c:enumerator:: PyImport_LAZY_NONE
|
||||
|
||||
Disable lazy imports entirely. Even explicit ``lazy`` statements become
|
||||
eager imports.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
.. c:function:: PyObject* PyImport_CreateModuleFromInitfunc(PyObject *spec, PyObject* (*initfunc)(void))
|
||||
|
||||
This function is a building block that enables embedders to implement
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.. _c-api-index:
|
||||
|
||||
##################################
|
||||
Python/C API Reference Manual
|
||||
Python/C API reference manual
|
||||
##################################
|
||||
|
||||
This manual documents the API used by C and C++ programmers who want to write
|
||||
|
|
@ -21,7 +21,12 @@ document the API functions in detail.
|
|||
utilities.rst
|
||||
abstract.rst
|
||||
concrete.rst
|
||||
init.rst
|
||||
interp-lifecycle.rst
|
||||
threads.rst
|
||||
synchronization.rst
|
||||
tls.rst
|
||||
subinterpreters.rst
|
||||
profiling.rst
|
||||
init_config.rst
|
||||
memory.rst
|
||||
objimpl.rst
|
||||
|
|
|
|||
2766
Doc/c-api/init.rst
2766
Doc/c-api/init.rst
File diff suppressed because it is too large
Load diff
|
|
@ -544,9 +544,9 @@ Configuration Options
|
|||
|
||||
Visibility:
|
||||
|
||||
* Public: Can by get by :c:func:`PyConfig_Get` and set by
|
||||
* Public: Can be retrieved by :c:func:`PyConfig_Get` and set by
|
||||
:c:func:`PyConfig_Set`.
|
||||
* Read-only: Can by get by :c:func:`PyConfig_Get`, but cannot be set by
|
||||
* Read-only: Can be retrieved by :c:func:`PyConfig_Get`, but cannot be set by
|
||||
:c:func:`PyConfig_Set`.
|
||||
|
||||
|
||||
|
|
@ -1153,7 +1153,7 @@ PyConfig
|
|||
|
||||
Most ``PyConfig`` methods :ref:`preinitialize Python <c-preinit>` if needed.
|
||||
In that case, the Python preinitialization configuration
|
||||
(:c:type:`PyPreConfig`) in based on the :c:type:`PyConfig`. If configuration
|
||||
(:c:type:`PyPreConfig`) is based on the :c:type:`PyConfig`. If configuration
|
||||
fields which are in common with :c:type:`PyPreConfig` are tuned, they must
|
||||
be set before calling a :c:type:`PyConfig` method:
|
||||
|
||||
|
|
@ -1807,10 +1807,10 @@ PyConfig
|
|||
|
||||
.. c:member:: wchar_t* run_presite
|
||||
|
||||
``package.module`` path to module that should be imported before
|
||||
``site.py`` is run.
|
||||
``module`` or ``module:func`` entry point that should be executed before
|
||||
the :mod:`site` module is imported.
|
||||
|
||||
Set by the :option:`-X presite=package.module <-X>` command-line
|
||||
Set by the :option:`-X presite=module:func <-X>` command-line
|
||||
option and the :envvar:`PYTHON_PRESITE` environment variable.
|
||||
The command-line option takes precedence.
|
||||
|
||||
|
|
@ -2299,13 +2299,91 @@ Py_GetArgcArgv()
|
|||
|
||||
See also :c:member:`PyConfig.orig_argv` member.
|
||||
|
||||
Delaying main module execution
|
||||
==============================
|
||||
|
||||
In some embedding use cases, it may be desirable to separate interpreter initialization
|
||||
from the execution of the main module.
|
||||
Multi-Phase Initialization Private Provisional API
|
||||
==================================================
|
||||
|
||||
This separation can be achieved by setting ``PyConfig.run_command`` to the empty
|
||||
string during initialization (to prevent the interpreter from dropping into the
|
||||
interactive prompt), and then subsequently executing the desired main module
|
||||
code using ``__main__.__dict__`` as the global namespace.
|
||||
This section is a private provisional API introducing multi-phase
|
||||
initialization, the core feature of :pep:`432`:
|
||||
|
||||
* "Core" initialization phase, "bare minimum Python":
|
||||
|
||||
* Builtin types;
|
||||
* Builtin exceptions;
|
||||
* Builtin and frozen modules;
|
||||
* The :mod:`sys` module is only partially initialized
|
||||
(ex: :data:`sys.path` doesn't exist yet).
|
||||
|
||||
* "Main" initialization phase, Python is fully initialized:
|
||||
|
||||
* Install and configure :mod:`importlib`;
|
||||
* Apply the :ref:`Path Configuration <init-path-config>`;
|
||||
* Install signal handlers;
|
||||
* Finish :mod:`sys` module initialization (ex: create :data:`sys.stdout`
|
||||
and :data:`sys.path`);
|
||||
* Enable optional features like :mod:`faulthandler` and :mod:`tracemalloc`;
|
||||
* Import the :mod:`site` module;
|
||||
* etc.
|
||||
|
||||
Private provisional API:
|
||||
|
||||
.. c:member:: int PyConfig._init_main
|
||||
|
||||
If set to ``0``, :c:func:`Py_InitializeFromConfig` stops at the "Core"
|
||||
initialization phase.
|
||||
|
||||
.. c:function:: PyStatus _Py_InitializeMain(void)
|
||||
|
||||
Move to the "Main" initialization phase, finish the Python initialization.
|
||||
|
||||
No module is imported during the "Core" phase and the ``importlib`` module is
|
||||
not configured: the :ref:`Path Configuration <init-path-config>` is only
|
||||
applied during the "Main" phase. It may allow to customize Python in Python to
|
||||
override or tune the :ref:`Path Configuration <init-path-config>`, maybe
|
||||
install a custom :data:`sys.meta_path` importer or an import hook, etc.
|
||||
|
||||
It may become possible to calculate the :ref:`Path Configuration
|
||||
<init-path-config>` in Python, after the Core phase and before the Main phase,
|
||||
which is one of the :pep:`432` motivation.
|
||||
|
||||
The "Core" phase is not properly defined: what should be and what should
|
||||
not be available at this phase is not specified yet. The API is marked
|
||||
as private and provisional: the API can be modified or even be removed
|
||||
anytime until a proper public API is designed.
|
||||
|
||||
Example running Python code between "Core" and "Main" initialization
|
||||
phases::
|
||||
|
||||
void init_python(void)
|
||||
{
|
||||
PyStatus status;
|
||||
|
||||
PyConfig config;
|
||||
PyConfig_InitPythonConfig(&config);
|
||||
config._init_main = 0;
|
||||
|
||||
/* ... customize 'config' configuration ... */
|
||||
|
||||
status = Py_InitializeFromConfig(&config);
|
||||
PyConfig_Clear(&config);
|
||||
if (PyStatus_Exception(status)) {
|
||||
Py_ExitStatusException(status);
|
||||
}
|
||||
|
||||
/* Use sys.stderr because sys.stdout is only created
|
||||
by _Py_InitializeMain() */
|
||||
int res = PyRun_SimpleString(
|
||||
"import sys; "
|
||||
"print('Run Python code before _Py_InitializeMain', "
|
||||
"file=sys.stderr)");
|
||||
if (res < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* ... put more configuration code here ... */
|
||||
|
||||
status = _Py_InitializeMain();
|
||||
if (PyStatus_Exception(status)) {
|
||||
Py_ExitStatusException(status);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
802
Doc/c-api/interp-lifecycle.rst
Normal file
802
Doc/c-api/interp-lifecycle.rst
Normal file
|
|
@ -0,0 +1,802 @@
|
|||
.. highlight:: c
|
||||
|
||||
.. _initialization:
|
||||
|
||||
Interpreter initialization and finalization
|
||||
===========================================
|
||||
|
||||
See :ref:`Python Initialization Configuration <init-config>` for details
|
||||
on how to configure the interpreter prior to initialization.
|
||||
|
||||
.. _pre-init-safe:
|
||||
|
||||
Before Python initialization
|
||||
----------------------------
|
||||
|
||||
In an application embedding Python, the :c:func:`Py_Initialize` function must
|
||||
be called before using any other Python/C API functions; with the exception of
|
||||
a few functions and the :ref:`global configuration variables
|
||||
<global-conf-vars>`.
|
||||
|
||||
The following functions can be safely called before Python is initialized:
|
||||
|
||||
* Functions that initialize the interpreter:
|
||||
|
||||
* :c:func:`Py_Initialize`
|
||||
* :c:func:`Py_InitializeEx`
|
||||
* :c:func:`Py_InitializeFromConfig`
|
||||
* :c:func:`Py_BytesMain`
|
||||
* :c:func:`Py_Main`
|
||||
* the runtime pre-initialization functions covered in :ref:`init-config`
|
||||
|
||||
* Configuration functions:
|
||||
|
||||
* :c:func:`PyImport_AppendInittab`
|
||||
* :c:func:`PyImport_ExtendInittab`
|
||||
* :c:func:`!PyInitFrozenExtensions`
|
||||
* :c:func:`PyMem_SetAllocator`
|
||||
* :c:func:`PyMem_SetupDebugHooks`
|
||||
* :c:func:`PyObject_SetArenaAllocator`
|
||||
* :c:func:`Py_SetProgramName`
|
||||
* :c:func:`Py_SetPythonHome`
|
||||
* the configuration functions covered in :ref:`init-config`
|
||||
|
||||
* Informative functions:
|
||||
|
||||
* :c:func:`Py_IsInitialized`
|
||||
* :c:func:`PyMem_GetAllocator`
|
||||
* :c:func:`PyObject_GetArenaAllocator`
|
||||
* :c:func:`Py_GetBuildInfo`
|
||||
* :c:func:`Py_GetCompiler`
|
||||
* :c:func:`Py_GetCopyright`
|
||||
* :c:func:`Py_GetPlatform`
|
||||
* :c:func:`Py_GetVersion`
|
||||
* :c:func:`Py_IsInitialized`
|
||||
|
||||
* Utilities:
|
||||
|
||||
* :c:func:`Py_DecodeLocale`
|
||||
* the status reporting and utility functions covered in :ref:`init-config`
|
||||
|
||||
* Memory allocators:
|
||||
|
||||
* :c:func:`PyMem_RawMalloc`
|
||||
* :c:func:`PyMem_RawRealloc`
|
||||
* :c:func:`PyMem_RawCalloc`
|
||||
* :c:func:`PyMem_RawFree`
|
||||
|
||||
* Synchronization:
|
||||
|
||||
* :c:func:`PyMutex_Lock`
|
||||
* :c:func:`PyMutex_Unlock`
|
||||
|
||||
.. note::
|
||||
|
||||
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:`PyEval_InitThreads`, and
|
||||
:c:func:`Py_RunMain`.
|
||||
|
||||
|
||||
.. _global-conf-vars:
|
||||
|
||||
Global configuration variables
|
||||
------------------------------
|
||||
|
||||
Python has variables for the global configuration to control different features
|
||||
and options. By default, these flags are controlled by :ref:`command line
|
||||
options <using-on-interface-options>`.
|
||||
|
||||
When a flag is set by an option, the value of the flag is the number of times
|
||||
that the option was set. For example, ``-b`` sets :c:data:`Py_BytesWarningFlag`
|
||||
to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2.
|
||||
|
||||
|
||||
.. c:var:: int Py_BytesWarningFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.bytes_warning` should be used instead, see :ref:`Python
|
||||
Initialization Configuration <init-config>`.
|
||||
|
||||
Issue a warning when comparing :class:`bytes` or :class:`bytearray` with
|
||||
:class:`str` or :class:`bytes` with :class:`int`. Issue an error if greater
|
||||
or equal to ``2``.
|
||||
|
||||
Set by the :option:`-b` option.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_DebugFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.parser_debug` should be used instead, see :ref:`Python
|
||||
Initialization Configuration <init-config>`.
|
||||
|
||||
Turn on parser debugging output (for expert only, depending on compilation
|
||||
options).
|
||||
|
||||
Set by the :option:`-d` option and the :envvar:`PYTHONDEBUG` environment
|
||||
variable.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_DontWriteBytecodeFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.write_bytecode` should be used instead, see :ref:`Python
|
||||
Initialization Configuration <init-config>`.
|
||||
|
||||
If set to non-zero, Python won't try to write ``.pyc`` files on the
|
||||
import of source modules.
|
||||
|
||||
Set by the :option:`-B` option and the :envvar:`PYTHONDONTWRITEBYTECODE`
|
||||
environment variable.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_FrozenFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.pathconfig_warnings` should be used instead, see
|
||||
:ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
Private flag used by ``_freeze_module`` and ``frozenmain`` programs.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_HashRandomizationFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.hash_seed` and :c:member:`PyConfig.use_hash_seed` should
|
||||
be used instead, see :ref:`Python Initialization Configuration
|
||||
<init-config>`.
|
||||
|
||||
Set to ``1`` if the :envvar:`PYTHONHASHSEED` environment variable is set to
|
||||
a non-empty string.
|
||||
|
||||
If the flag is non-zero, read the :envvar:`PYTHONHASHSEED` environment
|
||||
variable to initialize the secret hash seed.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_IgnoreEnvironmentFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.use_environment` should be used instead, see
|
||||
:ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
Ignore all :envvar:`!PYTHON*` environment variables, e.g.
|
||||
:envvar:`PYTHONPATH` and :envvar:`PYTHONHOME`, that might be set.
|
||||
|
||||
Set by the :option:`-E` and :option:`-I` options.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_InspectFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.inspect` should be used instead, see
|
||||
:ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
When a script is passed as first argument or the :option:`-c` option is used,
|
||||
enter interactive mode after executing the script or the command, even when
|
||||
:data:`sys.stdin` does not appear to be a terminal.
|
||||
|
||||
Set by the :option:`-i` option and the :envvar:`PYTHONINSPECT` environment
|
||||
variable.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_InteractiveFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.interactive` should be used instead, see
|
||||
:ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
Set by the :option:`-i` option.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_IsolatedFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.isolated` should be used instead, see
|
||||
:ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
Run Python in isolated mode. In isolated mode :data:`sys.path` contains
|
||||
neither the script's directory nor the user's site-packages directory.
|
||||
|
||||
Set by the :option:`-I` option.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_LegacyWindowsFSEncodingFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyPreConfig.legacy_windows_fs_encoding` should be used instead, see
|
||||
:ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
If the flag is non-zero, use the ``mbcs`` encoding with ``replace`` error
|
||||
handler, instead of the UTF-8 encoding with ``surrogatepass`` error handler,
|
||||
for the :term:`filesystem encoding and error handler`.
|
||||
|
||||
Set to ``1`` if the :envvar:`PYTHONLEGACYWINDOWSFSENCODING` environment
|
||||
variable is set to a non-empty string.
|
||||
|
||||
See :pep:`529` for more details.
|
||||
|
||||
.. availability:: Windows.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_LegacyWindowsStdioFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.legacy_windows_stdio` should be used instead, see
|
||||
:ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
If the flag is non-zero, use :class:`io.FileIO` instead of
|
||||
:class:`!io._WindowsConsoleIO` for :mod:`sys` standard streams.
|
||||
|
||||
Set to ``1`` if the :envvar:`PYTHONLEGACYWINDOWSSTDIO` environment
|
||||
variable is set to a non-empty string.
|
||||
|
||||
See :pep:`528` for more details.
|
||||
|
||||
.. availability:: Windows.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_NoSiteFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.site_import` should be used instead, see
|
||||
:ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
Disable the import of the module :mod:`site` and the site-dependent
|
||||
manipulations of :data:`sys.path` that it entails. Also disable these
|
||||
manipulations if :mod:`site` is explicitly imported later (call
|
||||
:func:`site.main` if you want them to be triggered).
|
||||
|
||||
Set by the :option:`-S` option.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_NoUserSiteDirectory
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.user_site_directory` should be used instead, see
|
||||
:ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
Don't add the :data:`user site-packages directory <site.USER_SITE>` to
|
||||
:data:`sys.path`.
|
||||
|
||||
Set by the :option:`-s` and :option:`-I` options, and the
|
||||
:envvar:`PYTHONNOUSERSITE` environment variable.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_OptimizeFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.optimization_level` should be used instead, see
|
||||
:ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
Set by the :option:`-O` option and the :envvar:`PYTHONOPTIMIZE` environment
|
||||
variable.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_QuietFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.quiet` should be used instead, see :ref:`Python
|
||||
Initialization Configuration <init-config>`.
|
||||
|
||||
Don't display the copyright and version messages even in interactive mode.
|
||||
|
||||
Set by the :option:`-q` option.
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_UnbufferedStdioFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.buffered_stdio` should be used instead, see :ref:`Python
|
||||
Initialization Configuration <init-config>`.
|
||||
|
||||
Force the stdout and stderr streams to be unbuffered.
|
||||
|
||||
Set by the :option:`-u` option and the :envvar:`PYTHONUNBUFFERED`
|
||||
environment variable.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
.. c:var:: int Py_VerboseFlag
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.verbose` should be used instead, see :ref:`Python
|
||||
Initialization Configuration <init-config>`.
|
||||
|
||||
Print a message each time a module is initialized, showing the place
|
||||
(filename or built-in module) from which it is loaded. If greater or equal
|
||||
to ``2``, print a message for each file that is checked for when
|
||||
searching for a module. Also provides information on module cleanup at exit.
|
||||
|
||||
Set by the :option:`-v` option and the :envvar:`PYTHONVERBOSE` environment
|
||||
variable.
|
||||
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
|
||||
|
||||
Initializing and finalizing the interpreter
|
||||
-------------------------------------------
|
||||
|
||||
.. c:function:: void Py_Initialize()
|
||||
|
||||
.. index::
|
||||
single: PyEval_InitThreads()
|
||||
single: modules (in module sys)
|
||||
single: path (in module sys)
|
||||
pair: module; builtins
|
||||
pair: module; __main__
|
||||
pair: module; sys
|
||||
triple: module; search; path
|
||||
single: Py_FinalizeEx (C function)
|
||||
|
||||
Initialize the Python interpreter. In an application embedding Python,
|
||||
this should be called before using any other Python/C API functions; see
|
||||
:ref:`Before Python Initialization <pre-init-safe>` for the few exceptions.
|
||||
|
||||
This initializes the table of loaded modules (``sys.modules``), and creates
|
||||
the fundamental modules :mod:`builtins`, :mod:`__main__` and :mod:`sys`.
|
||||
It also initializes the module search path (``sys.path``). It does not set
|
||||
``sys.argv``; use the :ref:`Python Initialization Configuration <init-config>`
|
||||
API for that. This is a no-op when called for a second time (without calling
|
||||
:c:func:`Py_FinalizeEx` first). There is no return value; it is a fatal
|
||||
error if the initialization fails.
|
||||
|
||||
Use :c:func:`Py_InitializeFromConfig` to customize the
|
||||
:ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
.. note::
|
||||
On Windows, changes the console mode from ``O_TEXT`` to ``O_BINARY``,
|
||||
which will also affect non-Python uses of the console using the C Runtime.
|
||||
|
||||
|
||||
.. c:function:: void Py_InitializeEx(int initsigs)
|
||||
|
||||
This function works like :c:func:`Py_Initialize` if *initsigs* is ``1``. If
|
||||
*initsigs* is ``0``, it skips initialization registration of signal handlers,
|
||||
which may be useful when CPython is embedded as part of a larger application.
|
||||
|
||||
Use :c:func:`Py_InitializeFromConfig` to customize the
|
||||
:ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
|
||||
.. c:function:: PyStatus Py_InitializeFromConfig(const PyConfig *config)
|
||||
|
||||
Initialize Python from *config* configuration, as described in
|
||||
:ref:`init-from-config`.
|
||||
|
||||
See the :ref:`init-config` section for details on pre-initializing the
|
||||
interpreter, populating the runtime configuration structure, and querying
|
||||
the returned status structure.
|
||||
|
||||
|
||||
.. c:function:: int Py_IsInitialized()
|
||||
|
||||
Return true (nonzero) when the Python interpreter has been initialized, false
|
||||
(zero) if not. After :c:func:`Py_FinalizeEx` is called, this returns false until
|
||||
:c:func:`Py_Initialize` is called again.
|
||||
|
||||
.. versionchanged:: next
|
||||
This function no longer returns true until initialization has fully
|
||||
completed, including import of the :mod:`site` module. Previously it
|
||||
could return true while :c:func:`Py_Initialize` was still running.
|
||||
|
||||
|
||||
.. c:function:: int Py_IsFinalizing()
|
||||
|
||||
Return true (non-zero) if the main Python interpreter is
|
||||
:term:`shutting down <interpreter shutdown>`. Return false (zero) otherwise.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:function:: int Py_FinalizeEx()
|
||||
|
||||
Undo all initializations made by :c:func:`Py_Initialize` and subsequent use of
|
||||
Python/C API functions, and destroy all sub-interpreters (see
|
||||
:c:func:`Py_NewInterpreter` below) that were created and not yet destroyed since
|
||||
the last call to :c:func:`Py_Initialize`. This is a no-op when called for a second
|
||||
time (without calling :c:func:`Py_Initialize` again first).
|
||||
|
||||
Since this is the reverse of :c:func:`Py_Initialize`, it should be called
|
||||
in the same thread with the same interpreter active. That means
|
||||
the main thread and the main interpreter.
|
||||
This should never be called while :c:func:`Py_RunMain` is running.
|
||||
|
||||
Normally the return value is ``0``.
|
||||
If there were errors during finalization (flushing buffered data),
|
||||
``-1`` is returned.
|
||||
|
||||
Note that Python will do a best effort at freeing all memory allocated by the Python
|
||||
interpreter. Therefore, any C-Extension should make sure to correctly clean up all
|
||||
of the previously allocated PyObjects before using them in subsequent calls to
|
||||
:c:func:`Py_Initialize`. Otherwise it could introduce vulnerabilities and incorrect
|
||||
behavior.
|
||||
|
||||
This function is provided for a number of reasons. An embedding application
|
||||
might want to restart Python without having to restart the application itself.
|
||||
An application that has loaded the Python interpreter from a dynamically
|
||||
loadable library (or DLL) might want to free all memory allocated by Python
|
||||
before unloading the DLL. During a hunt for memory leaks in an application a
|
||||
developer might want to free all memory allocated by Python before exiting from
|
||||
the application.
|
||||
|
||||
**Bugs and caveats:** The destruction of modules and objects in modules is done
|
||||
in random order; this may cause destructors (:meth:`~object.__del__` methods) to fail
|
||||
when they depend on other objects (even functions) or modules. Dynamically
|
||||
loaded extension modules loaded by Python are not unloaded. Small amounts of
|
||||
memory allocated by the Python interpreter may not be freed (if you find a leak,
|
||||
please report it). Memory tied up in circular references between objects is not
|
||||
freed. Interned strings will all be deallocated regardless of their reference count.
|
||||
Some memory allocated by extension modules may not be freed. Some extensions may not
|
||||
work properly if their initialization routine is called more than once; this can
|
||||
happen if an application calls :c:func:`Py_Initialize` and :c:func:`Py_FinalizeEx`
|
||||
more than once. :c:func:`Py_FinalizeEx` must not be called recursively from
|
||||
within itself. Therefore, it must not be called by any code that may be run
|
||||
as part of the interpreter shutdown process, such as :py:mod:`atexit`
|
||||
handlers, object finalizers, or any code that may be run while flushing the
|
||||
stdout and stderr files.
|
||||
|
||||
.. audit-event:: cpython._PySys_ClearAuditHooks "" c.Py_FinalizeEx
|
||||
|
||||
.. versionadded:: 3.6
|
||||
|
||||
|
||||
.. c:function:: void Py_Finalize()
|
||||
|
||||
This is a backwards-compatible version of :c:func:`Py_FinalizeEx` that
|
||||
disregards the return value.
|
||||
|
||||
|
||||
.. c:function:: int Py_BytesMain(int argc, char **argv)
|
||||
|
||||
Similar to :c:func:`Py_Main` but *argv* is an array of bytes strings,
|
||||
allowing the calling application to delegate the text decoding step to
|
||||
the CPython runtime.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
.. c:function:: int Py_Main(int argc, wchar_t **argv)
|
||||
|
||||
The main program for the standard interpreter, encapsulating a full
|
||||
initialization/finalization cycle, as well as additional
|
||||
behaviour to implement reading configurations settings from the environment
|
||||
and command line, and then executing ``__main__`` in accordance with
|
||||
:ref:`using-on-cmdline`.
|
||||
|
||||
This is made available for programs which wish to support the full CPython
|
||||
command line interface, rather than just embedding a Python runtime in a
|
||||
larger application.
|
||||
|
||||
The *argc* and *argv* parameters are similar to those which are passed to a
|
||||
C program's :c:func:`main` function, except that the *argv* entries are first
|
||||
converted to ``wchar_t`` using :c:func:`Py_DecodeLocale`. It is also
|
||||
important to note that the argument list entries may be modified to point to
|
||||
strings other than those passed in (however, the contents of the strings
|
||||
pointed to by the argument list are not modified).
|
||||
|
||||
The return value is ``2`` if the argument list does not represent a valid
|
||||
Python command line, and otherwise the same as :c:func:`Py_RunMain`.
|
||||
|
||||
In terms of the CPython runtime configuration APIs documented in the
|
||||
:ref:`runtime configuration <init-config>` section (and without accounting
|
||||
for error handling), ``Py_Main`` is approximately equivalent to::
|
||||
|
||||
PyConfig config;
|
||||
PyConfig_InitPythonConfig(&config);
|
||||
PyConfig_SetArgv(&config, argc, argv);
|
||||
Py_InitializeFromConfig(&config);
|
||||
PyConfig_Clear(&config);
|
||||
|
||||
Py_RunMain();
|
||||
|
||||
In normal usage, an embedding application will call this function
|
||||
*instead* of calling :c:func:`Py_Initialize`, :c:func:`Py_InitializeEx` or
|
||||
:c:func:`Py_InitializeFromConfig` directly, and all settings will be applied
|
||||
as described elsewhere in this documentation. If this function is instead
|
||||
called *after* a preceding runtime initialization API call, then exactly
|
||||
which environmental and command line configuration settings will be updated
|
||||
is version dependent (as it depends on which settings correctly support
|
||||
being modified after they have already been set once when the runtime was
|
||||
first initialized).
|
||||
|
||||
|
||||
.. c:function:: int Py_RunMain(void)
|
||||
|
||||
Executes the main module in a fully configured CPython runtime.
|
||||
|
||||
Executes the command (:c:member:`PyConfig.run_command`), the script
|
||||
(:c:member:`PyConfig.run_filename`) or the module
|
||||
(:c:member:`PyConfig.run_module`) specified on the command line or in the
|
||||
configuration. If none of these values are set, runs the interactive Python
|
||||
prompt (REPL) using the ``__main__`` module's global namespace.
|
||||
|
||||
If :c:member:`PyConfig.inspect` is not set (the default), the return value
|
||||
will be ``0`` if the interpreter exits normally (that is, without raising
|
||||
an exception), the exit status of an unhandled :exc:`SystemExit`, or ``1``
|
||||
for any other unhandled exception.
|
||||
|
||||
If :c:member:`PyConfig.inspect` is set (such as when the :option:`-i` option
|
||||
is used), rather than returning when the interpreter exits, execution will
|
||||
instead resume in an interactive Python prompt (REPL) using the ``__main__``
|
||||
module's global namespace. If the interpreter exited with an exception, it
|
||||
is immediately raised in the REPL session. The function return value is
|
||||
then determined by the way the *REPL session* terminates: ``0``, ``1``, or
|
||||
the status of a :exc:`SystemExit`, as specified above.
|
||||
|
||||
This function always finalizes the Python interpreter before it returns.
|
||||
|
||||
See :ref:`Python Configuration <init-python-config>` for an example of a
|
||||
customized Python that always runs in isolated mode using
|
||||
:c:func:`Py_RunMain`.
|
||||
|
||||
.. c:function:: int PyUnstable_AtExit(PyInterpreterState *interp, void (*func)(void *), void *data)
|
||||
|
||||
Register an :mod:`atexit` callback for the target interpreter *interp*.
|
||||
This is similar to :c:func:`Py_AtExit`, but takes an explicit interpreter and
|
||||
data pointer for the callback.
|
||||
|
||||
There must be an :term:`attached thread state` for *interp*.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. _cautions-regarding-runtime-finalization:
|
||||
|
||||
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
|
||||
: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 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 :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.
|
||||
|
||||
|
||||
Process-wide parameters
|
||||
-----------------------
|
||||
|
||||
.. c:function:: void Py_SetProgramName(const wchar_t *name)
|
||||
|
||||
.. index::
|
||||
single: Py_Initialize()
|
||||
single: main()
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.program_name` should be used instead, see :ref:`Python
|
||||
Initialization Configuration <init-config>`.
|
||||
|
||||
This function should be called before :c:func:`Py_Initialize` is called for
|
||||
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 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
|
||||
change for the duration of the program's execution. No code in the Python
|
||||
interpreter will change the contents of this storage.
|
||||
|
||||
Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a
|
||||
:c:expr:`wchar_t*` string.
|
||||
|
||||
.. deprecated-removed:: 3.11 3.15
|
||||
|
||||
|
||||
.. c:function:: const char* Py_GetVersion()
|
||||
|
||||
Return the version of this Python interpreter. This is a string that looks
|
||||
something like ::
|
||||
|
||||
"3.0a5+ (py3k:63103M, May 12 2008, 00:53:55) \n[GCC 4.2.3]"
|
||||
|
||||
.. index:: single: version (in module sys)
|
||||
|
||||
The first word (up to the first space character) is the current Python version;
|
||||
the first characters are the major and minor version separated by a
|
||||
period. The returned string points into static storage; the caller should not
|
||||
modify its value. The value is available to Python code as :data:`sys.version`.
|
||||
|
||||
See also the :c:var:`Py_Version` constant.
|
||||
|
||||
|
||||
.. c:function:: const char* Py_GetPlatform()
|
||||
|
||||
.. index:: single: platform (in module sys)
|
||||
|
||||
Return the platform identifier for the current platform. On Unix, this is
|
||||
formed from the "official" name of the operating system, converted to lower
|
||||
case, followed by the major revision number; e.g., for Solaris 2.x, which is
|
||||
also known as SunOS 5.x, the value is ``'sunos5'``. On macOS, it is
|
||||
``'darwin'``. On Windows, it is ``'win'``. The returned string points into
|
||||
static storage; the caller should not modify its value. The value is available
|
||||
to Python code as ``sys.platform``.
|
||||
|
||||
|
||||
.. c:function:: const char* Py_GetCopyright()
|
||||
|
||||
Return the official copyright string for the current Python version, for example
|
||||
|
||||
``'Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam'``
|
||||
|
||||
.. index:: single: copyright (in module sys)
|
||||
|
||||
The returned string points into static storage; the caller should not modify its
|
||||
value. The value is available to Python code as ``sys.copyright``.
|
||||
|
||||
|
||||
.. c:function:: const char* Py_GetCompiler()
|
||||
|
||||
Return an indication of the compiler used to build the current Python version,
|
||||
in square brackets, for example::
|
||||
|
||||
"[GCC 2.7.2.2]"
|
||||
|
||||
.. index:: single: version (in module sys)
|
||||
|
||||
The returned string points into static storage; the caller should not modify its
|
||||
value. The value is available to Python code as part of the variable
|
||||
``sys.version``.
|
||||
|
||||
|
||||
.. c:function:: const char* Py_GetBuildInfo()
|
||||
|
||||
Return information about the sequence number and build date and time of the
|
||||
current Python interpreter instance, for example ::
|
||||
|
||||
"#67, Aug 1 1997, 22:34:28"
|
||||
|
||||
.. index:: single: version (in module sys)
|
||||
|
||||
The returned string points into static storage; the caller should not modify its
|
||||
value. The value is available to Python code as part of the variable
|
||||
``sys.version``.
|
||||
|
||||
|
||||
.. c:function:: void PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath)
|
||||
|
||||
.. index::
|
||||
single: main()
|
||||
single: Py_FatalError()
|
||||
single: argv (in module sys)
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.argv`, :c:member:`PyConfig.parse_argv` and
|
||||
:c:member:`PyConfig.safe_path` should be used instead, see :ref:`Python
|
||||
Initialization Configuration <init-config>`.
|
||||
|
||||
Set :data:`sys.argv` based on *argc* and *argv*. These parameters are
|
||||
similar to those passed to the program's :c:func:`main` function with the
|
||||
difference that the first entry should refer to the script file to be
|
||||
executed rather than the executable hosting the Python interpreter. If there
|
||||
isn't a script that will be run, the first entry in *argv* can be an empty
|
||||
string. If this function fails to initialize :data:`sys.argv`, a fatal
|
||||
condition is signalled using :c:func:`Py_FatalError`.
|
||||
|
||||
If *updatepath* is zero, this is all the function does. If *updatepath*
|
||||
is non-zero, the function also modifies :data:`sys.path` according to the
|
||||
following algorithm:
|
||||
|
||||
- If the name of an existing script is passed in ``argv[0]``, the absolute
|
||||
path of the directory where the script is located is prepended to
|
||||
:data:`sys.path`.
|
||||
- Otherwise (that is, if *argc* is ``0`` or ``argv[0]`` doesn't point
|
||||
to an existing file name), an empty string is prepended to
|
||||
:data:`sys.path`, which is the same as prepending the current working
|
||||
directory (``"."``).
|
||||
|
||||
Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a
|
||||
:c:expr:`wchar_t*` string.
|
||||
|
||||
See also :c:member:`PyConfig.orig_argv` and :c:member:`PyConfig.argv`
|
||||
members of the :ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
.. note::
|
||||
It is recommended that applications embedding the Python interpreter
|
||||
for purposes other than executing a single script pass ``0`` as *updatepath*,
|
||||
and update :data:`sys.path` themselves if desired.
|
||||
See :cve:`2008-5983`.
|
||||
|
||||
On versions before 3.1.3, you can achieve the same effect by manually
|
||||
popping the first :data:`sys.path` element after having called
|
||||
:c:func:`PySys_SetArgv`, for example using::
|
||||
|
||||
PyRun_SimpleString("import sys; sys.path.pop(0)\n");
|
||||
|
||||
.. versionadded:: 3.1.3
|
||||
|
||||
.. deprecated-removed:: 3.11 3.15
|
||||
|
||||
|
||||
.. c:function:: void PySys_SetArgv(int argc, wchar_t **argv)
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.argv` and :c:member:`PyConfig.parse_argv` should be used
|
||||
instead, see :ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
This function works like :c:func:`PySys_SetArgvEx` with *updatepath* set
|
||||
to ``1`` unless the :program:`python` interpreter was started with the
|
||||
:option:`-I`.
|
||||
|
||||
Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a
|
||||
:c:expr:`wchar_t*` string.
|
||||
|
||||
See also :c:member:`PyConfig.orig_argv` and :c:member:`PyConfig.argv`
|
||||
members of the :ref:`Python Initialization Configuration <init-config>`.
|
||||
|
||||
.. versionchanged:: 3.4 The *updatepath* value depends on :option:`-I`.
|
||||
|
||||
.. deprecated-removed:: 3.11 3.15
|
||||
|
||||
|
||||
.. c:function:: void Py_SetPythonHome(const wchar_t *home)
|
||||
|
||||
This API is kept for backward compatibility: setting
|
||||
:c:member:`PyConfig.home` should be used instead, see :ref:`Python
|
||||
Initialization Configuration <init-config>`.
|
||||
|
||||
Set the default "home" directory, that is, the location of the standard
|
||||
Python libraries. See :envvar:`PYTHONHOME` for the meaning of the
|
||||
argument string.
|
||||
|
||||
The argument should point to a zero-terminated character string in static
|
||||
storage whose contents will not change for the duration of the program's
|
||||
execution. No code in the Python interpreter will change the contents of
|
||||
this storage.
|
||||
|
||||
Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a
|
||||
:c:expr:`wchar_t*` string.
|
||||
|
||||
.. deprecated-removed:: 3.11 3.15
|
||||
|
|
@ -123,6 +123,7 @@ System includes
|
|||
* ``<limits.h>``
|
||||
* ``<math.h>``
|
||||
* ``<stdarg.h>``
|
||||
* ``<string.h>``
|
||||
* ``<wchar.h>``
|
||||
* ``<sys/types.h>`` (if present)
|
||||
|
||||
|
|
@ -138,7 +139,6 @@ System includes
|
|||
* ``<errno.h>``
|
||||
* ``<stdio.h>``
|
||||
* ``<stdlib.h>``
|
||||
* ``<string.h>``
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
@ -156,28 +156,126 @@ defined closer to where they are useful (for example, :c:macro:`Py_RETURN_NONE`,
|
|||
Others of a more general utility are defined here. This is not necessarily a
|
||||
complete listing.
|
||||
|
||||
.. c:macro:: Py_CAN_START_THREADS
|
||||
|
||||
If this macro is defined, then the current system is able to start threads.
|
||||
|
||||
Currently, all systems supported by CPython (per :pep:`11`), with the
|
||||
exception of some WebAssembly platforms, support starting threads.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. c:macro:: Py_GETENV(s)
|
||||
|
||||
Like :samp:`getenv({s})`, but returns ``NULL`` if :option:`-E` was passed
|
||||
on the command line (see :c:member:`PyConfig.use_environment`).
|
||||
|
||||
|
||||
Docstring macros
|
||||
----------------
|
||||
|
||||
.. c:macro:: PyDoc_STRVAR(name, str)
|
||||
|
||||
Creates a variable with name *name* that can be used in docstrings.
|
||||
If Python is built without docstrings (:option:`--without-doc-strings`),
|
||||
the value will be an empty string.
|
||||
|
||||
Example::
|
||||
|
||||
PyDoc_STRVAR(pop_doc, "Remove and return the rightmost element.");
|
||||
|
||||
static PyMethodDef deque_methods[] = {
|
||||
// ...
|
||||
{"pop", (PyCFunction)deque_pop, METH_NOARGS, pop_doc},
|
||||
// ...
|
||||
}
|
||||
|
||||
Expands to :samp:`PyDoc_VAR({name}) = PyDoc_STR({str})`.
|
||||
|
||||
.. c:macro:: PyDoc_STR(str)
|
||||
|
||||
Expands to the given input string, or an empty string
|
||||
if docstrings are disabled (:option:`--without-doc-strings`).
|
||||
|
||||
Example::
|
||||
|
||||
static PyMethodDef pysqlite_row_methods[] = {
|
||||
{"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS,
|
||||
PyDoc_STR("Returns the keys of the row.")},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
.. c:macro:: PyDoc_VAR(name)
|
||||
|
||||
Declares a static character array variable with the given *name*.
|
||||
Expands to :samp:`static const char {name}[]`
|
||||
|
||||
For example::
|
||||
|
||||
PyDoc_VAR(python_doc) = PyDoc_STR(
|
||||
"A genus of constricting snakes in the Pythonidae family native "
|
||||
"to the tropics and subtropics of the Eastern Hemisphere.");
|
||||
|
||||
|
||||
General utility macros
|
||||
----------------------
|
||||
|
||||
The following macros are for common tasks not specific to Python.
|
||||
|
||||
.. c:macro:: Py_UNUSED(arg)
|
||||
|
||||
Use this for unused arguments in a function definition to silence compiler
|
||||
warnings. Example: ``int func(int a, int Py_UNUSED(b)) { return a; }``.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
.. c:macro:: Py_GCC_ATTRIBUTE(name)
|
||||
|
||||
Use a GCC attribute *name*, hiding it from compilers that don't support GCC
|
||||
attributes (such as MSVC).
|
||||
|
||||
This expands to :samp:`__attribute__(({name)})` on a GCC compiler,
|
||||
and expands to nothing on compilers that don't support GCC attributes.
|
||||
|
||||
|
||||
Numeric utilities
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. c:macro:: Py_ABS(x)
|
||||
|
||||
Return the absolute value of ``x``.
|
||||
|
||||
The argument may be evaluated more than once.
|
||||
Consequently, do not pass an expression with side-effects directly
|
||||
to this macro.
|
||||
|
||||
If the result cannot be represented (for example, if ``x`` has
|
||||
:c:macro:`!INT_MIN` value for :c:expr:`int` type), the behavior is
|
||||
undefined.
|
||||
|
||||
Corresponds roughly to :samp:`(({x}) < 0 ? -({x}) : ({x}))`
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. c:macro:: Py_ALIGNED(num)
|
||||
.. c:macro:: Py_MAX(x, y)
|
||||
Py_MIN(x, y)
|
||||
|
||||
Specify alignment to *num* bytes on compilers that support it.
|
||||
Return the larger or smaller of the arguments, respectively.
|
||||
|
||||
Consider using the C11 standard ``_Alignas`` specifier over this macro.
|
||||
Any arguments may be evaluated more than once.
|
||||
Consequently, do not pass an expression with side-effects directly
|
||||
to this macro.
|
||||
|
||||
:c:macro:`!Py_MAX` corresponds roughly to
|
||||
:samp:`((({x}) > ({y})) ? ({x}) : ({y}))`.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. c:macro:: Py_ARITHMETIC_RIGHT_SHIFT(type, integer, positions)
|
||||
|
||||
Similar to ``integer >> positions``, but forces sign extension, as the C
|
||||
standard does not define whether a right-shift of a signed integer will
|
||||
perform sign extension or a zero-fill.
|
||||
Similar to :samp:`{integer} >> {positions}`, but forces sign extension,
|
||||
as the C standard does not define whether a right-shift of a signed
|
||||
integer will perform sign extension or a zero-fill.
|
||||
|
||||
*integer* should be any signed integer type.
|
||||
*positions* is the number of positions to shift to the right.
|
||||
|
|
@ -196,170 +294,14 @@ complete listing.
|
|||
which ``unsigned type`` is legal. As a result, *type* is no longer
|
||||
used.
|
||||
|
||||
.. c:macro:: Py_ALWAYS_INLINE
|
||||
|
||||
Ask the compiler to always inline a static inline function. The compiler can
|
||||
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,
|
||||
MSC disables function inlining when building in debug mode.
|
||||
|
||||
Marking blindly a static inline function with Py_ALWAYS_INLINE can result in
|
||||
worse performances (due to increased code size for example). The compiler is
|
||||
usually smarter than the developer for the cost/benefit analysis.
|
||||
|
||||
If Python is :ref:`built in debug mode <debug-build>` (if the :c:macro:`Py_DEBUG`
|
||||
macro is defined), the :c:macro:`Py_ALWAYS_INLINE` macro does nothing.
|
||||
|
||||
It must be specified before the function return type. Usage::
|
||||
|
||||
static inline Py_ALWAYS_INLINE int random(void) { return 4; }
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
.. c:macro:: Py_CAN_START_THREADS
|
||||
|
||||
If this macro is defined, then the current system is able to start threads.
|
||||
|
||||
Currently, all systems supported by CPython (per :pep:`11`), with the
|
||||
exception of some WebAssembly platforms, support starting threads.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. c:macro:: Py_CHARMASK(c)
|
||||
|
||||
Argument must be a character or an integer in the range [-128, 127] or [0,
|
||||
255]. This macro returns ``c`` cast to an ``unsigned char``.
|
||||
|
||||
.. c:macro:: Py_DEPRECATED(version)
|
||||
|
||||
Use this for deprecated declarations. The macro must be placed before the
|
||||
symbol name.
|
||||
|
||||
Example::
|
||||
|
||||
Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);
|
||||
|
||||
.. versionchanged:: 3.8
|
||||
MSVC support was added.
|
||||
|
||||
.. c:macro:: Py_FORCE_EXPANSION(X)
|
||||
|
||||
This is equivalent to ``X``, which is useful for token-pasting in
|
||||
macros, as macro expansions in *X* are forcefully evaluated by the
|
||||
preprocessor.
|
||||
|
||||
.. c:macro:: Py_GCC_ATTRIBUTE(name)
|
||||
|
||||
Use a GCC attribute *name*, hiding it from compilers that don't support GCC
|
||||
attributes (such as MSVC).
|
||||
|
||||
This expands to ``__attribute__((name))`` on a GCC compiler, and expands
|
||||
to nothing on compilers that don't support GCC attributes.
|
||||
|
||||
.. c:macro:: Py_GETENV(s)
|
||||
|
||||
Like ``getenv(s)``, but returns ``NULL`` if :option:`-E` was passed on the
|
||||
command line (see :c:member:`PyConfig.use_environment`).
|
||||
|
||||
.. c:macro:: Py_LL(number)
|
||||
|
||||
Use *number* as a ``long long`` integer literal.
|
||||
|
||||
This usally expands to *number* followed by ``LL``, but will expand to some
|
||||
compiler-specific suffixes (such as ``I64``) on older compilers.
|
||||
|
||||
In modern versions of Python, this macro is not very useful, as C99 and
|
||||
later require the ``LL`` suffix to be valid for an integer.
|
||||
|
||||
.. c:macro:: Py_LOCAL(type)
|
||||
|
||||
Declare a function returning the specified *type* using a fast-calling
|
||||
qualifier for functions that are local to the current file.
|
||||
Semantically, this is equivalent to ``static type``.
|
||||
|
||||
.. c:macro:: Py_LOCAL_INLINE(type)
|
||||
|
||||
Equivalent to :c:macro:`Py_LOCAL` but additionally requests the function
|
||||
be inlined.
|
||||
|
||||
.. c:macro:: Py_LOCAL_SYMBOL
|
||||
|
||||
Macro used to declare a symbol as local to the shared library (hidden).
|
||||
On supported platforms, it ensures the symbol is not exported.
|
||||
|
||||
On compatible versions of GCC/Clang, it
|
||||
expands to ``__attribute__((visibility("hidden")))``.
|
||||
|
||||
.. c:macro:: Py_MAX(x, y)
|
||||
|
||||
Return the maximum value between ``x`` and ``y``.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. c:macro:: Py_MEMBER_SIZE(type, member)
|
||||
|
||||
Return the size of a structure (``type``) ``member`` in bytes.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
|
||||
.. c:macro:: Py_MEMCPY(dest, src, n)
|
||||
|
||||
This is a :term:`soft deprecated` alias to :c:func:`!memcpy`.
|
||||
Use :c:func:`!memcpy` directly instead.
|
||||
|
||||
.. deprecated:: 3.14
|
||||
The macro is :term:`soft deprecated`.
|
||||
|
||||
.. c:macro:: Py_MIN(x, y)
|
||||
|
||||
Return the minimum value between ``x`` and ``y``.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. c:macro:: Py_NO_INLINE
|
||||
|
||||
Disable inlining on a function. For example, it reduces the C stack
|
||||
consumption: useful on LTO+PGO builds which heavily inline code (see
|
||||
:issue:`33720`).
|
||||
|
||||
Usage::
|
||||
|
||||
Py_NO_INLINE static int random(void) { return 4; }
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
.. c:macro:: Py_SAFE_DOWNCAST(value, larger, smaller)
|
||||
|
||||
Cast *value* to type *smaller* from type *larger*, validating that no
|
||||
information was lost.
|
||||
|
||||
On release builds of Python, this is roughly equivalent to
|
||||
``(smaller) value`` (in C++, ``static_cast<smaller>(value)`` will be
|
||||
used instead).
|
||||
|
||||
On debug builds (implying that :c:macro:`Py_DEBUG` is defined), this asserts
|
||||
that no information was lost with the cast from *larger* to *smaller*.
|
||||
|
||||
*value*, *larger*, and *smaller* may all be evaluated more than once in the
|
||||
expression; consequently, do not pass an expression with side-effects directly to
|
||||
this macro.
|
||||
|
||||
.. c:macro:: Py_STRINGIFY(x)
|
||||
|
||||
Convert ``x`` to a C string. E.g. ``Py_STRINGIFY(123)`` returns
|
||||
``"123"``.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
.. c:macro:: Py_ULL(number)
|
||||
|
||||
Similar to :c:macro:`Py_LL`, but *number* will be an ``unsigned long long``
|
||||
literal instead. This is done by appending ``U`` to the result of ``Py_LL``.
|
||||
|
||||
In modern versions of Python, this macro is not very useful, as C99 and
|
||||
later require the ``ULL``/``LLU`` suffixes to be valid for an integer.
|
||||
Assertion utilities
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. c:macro:: Py_UNREACHABLE()
|
||||
|
||||
|
|
@ -372,8 +314,11 @@ complete listing.
|
|||
avoids a warning about unreachable code. For example, the macro is
|
||||
implemented with ``__builtin_unreachable()`` on GCC in release mode.
|
||||
|
||||
A use for ``Py_UNREACHABLE()`` is following a call a function that
|
||||
never returns but that is not declared :c:macro:`_Py_NO_RETURN`.
|
||||
In debug mode, and on unsupported compilers, the macro expands to a call to
|
||||
:c:func:`Py_FatalError`.
|
||||
|
||||
A use for ``Py_UNREACHABLE()`` is following a call to a function that
|
||||
never returns but that is not declared ``_Noreturn``.
|
||||
|
||||
If a code path is very unlikely code but can be reached under exceptional
|
||||
case, this macro must not be used. For example, under low memory condition
|
||||
|
|
@ -383,18 +328,29 @@ complete listing.
|
|||
|
||||
.. versionadded:: 3.7
|
||||
|
||||
.. c:macro:: Py_UNUSED(arg)
|
||||
.. c:macro:: Py_SAFE_DOWNCAST(value, larger, smaller)
|
||||
|
||||
Use this for unused arguments in a function definition to silence compiler
|
||||
warnings. Example: ``int func(int a, int Py_UNUSED(b)) { return a; }``.
|
||||
Cast *value* to type *smaller* from type *larger*, validating that no
|
||||
information was lost.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
On release builds of Python, this is roughly equivalent to
|
||||
:samp:`(({smaller}) {value})`
|
||||
(in C++, :samp:`static_cast<{smaller}>({value})` will be used instead).
|
||||
|
||||
On debug builds (implying that :c:macro:`Py_DEBUG` is defined), this asserts
|
||||
that no information was lost with the cast from *larger* to *smaller*.
|
||||
|
||||
*value*, *larger*, and *smaller* may all be evaluated more than once in the
|
||||
expression; consequently, do not pass an expression with side-effects
|
||||
directly to this macro.
|
||||
|
||||
.. c:macro:: Py_BUILD_ASSERT(cond)
|
||||
|
||||
Asserts a compile-time condition *cond*, as a statement.
|
||||
The build will fail if the condition is false or cannot be evaluated at compile time.
|
||||
|
||||
Corresponds roughly to :samp:`static_assert({cond})` on C23 and above.
|
||||
|
||||
For example::
|
||||
|
||||
Py_BUILD_ASSERT(sizeof(PyTime_t) == sizeof(int64_t));
|
||||
|
|
@ -413,48 +369,9 @@ complete listing.
|
|||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. c:macro:: PyDoc_STRVAR(name, str)
|
||||
|
||||
Creates a variable with name *name* that can be used in docstrings.
|
||||
If Python is built without docstrings, the value will be empty.
|
||||
|
||||
Use :c:macro:`PyDoc_STRVAR` for docstrings to support building
|
||||
Python without docstrings, as specified in :pep:`7`.
|
||||
|
||||
Example::
|
||||
|
||||
PyDoc_STRVAR(pop_doc, "Remove and return the rightmost element.");
|
||||
|
||||
static PyMethodDef deque_methods[] = {
|
||||
// ...
|
||||
{"pop", (PyCFunction)deque_pop, METH_NOARGS, pop_doc},
|
||||
// ...
|
||||
}
|
||||
|
||||
.. c:macro:: PyDoc_STR(str)
|
||||
|
||||
Creates a docstring for the given input string or an empty string
|
||||
if docstrings are disabled.
|
||||
|
||||
Use :c:macro:`PyDoc_STR` in specifying docstrings to support
|
||||
building Python without docstrings, as specified in :pep:`7`.
|
||||
|
||||
Example::
|
||||
|
||||
static PyMethodDef pysqlite_row_methods[] = {
|
||||
{"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS,
|
||||
PyDoc_STR("Returns the keys of the row.")},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
.. c:macro:: PyDoc_VAR(name)
|
||||
|
||||
Declares a static character array variable with the given name *name*.
|
||||
|
||||
For example::
|
||||
|
||||
PyDoc_VAR(python_doc) = PyDoc_STR("A genus of constricting snakes in the Pythonidae family native "
|
||||
"to the tropics and subtropics of the Eastern Hemisphere.");
|
||||
Type size utilities
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. c:macro:: Py_ARRAY_LENGTH(array)
|
||||
|
||||
|
|
@ -469,6 +386,110 @@ complete listing.
|
|||
|
||||
sizeof(array) / sizeof((array)[0])
|
||||
|
||||
.. c:macro:: Py_MEMBER_SIZE(type, member)
|
||||
|
||||
Return the size of a structure (*type*) *member* in bytes.
|
||||
|
||||
Corresponds roughly to :samp:`sizeof((({type} *)NULL)->{member})`.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
|
||||
|
||||
Macro definition utilities
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. c:macro:: Py_FORCE_EXPANSION(X)
|
||||
|
||||
This is equivalent to :samp:`{X}`, which is useful for token-pasting in
|
||||
macros, as macro expansions in *X* are forcefully evaluated by the
|
||||
preprocessor.
|
||||
|
||||
.. c:macro:: Py_STRINGIFY(x)
|
||||
|
||||
Convert ``x`` to a C string. For example, ``Py_STRINGIFY(123)`` returns
|
||||
``"123"``.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
|
||||
Declaration utilities
|
||||
---------------------
|
||||
|
||||
The following macros can be used in declarations.
|
||||
They are most useful for defining the C API itself, and have limited use
|
||||
for extension authors.
|
||||
Most of them expand to compiler-specific spellings of common extensions
|
||||
to the C language.
|
||||
|
||||
.. c:macro:: Py_ALWAYS_INLINE
|
||||
|
||||
Ask the compiler to always inline a static inline function. The compiler can
|
||||
ignore it and decide to not inline the function.
|
||||
|
||||
Corresponds to ``always_inline`` attribute in GCC and ``__forceinline``
|
||||
in MSVC.
|
||||
|
||||
It can be used to inline performance critical static inline functions when
|
||||
building Python in debug mode with function inlining disabled. For example,
|
||||
MSC disables function inlining when building in debug mode.
|
||||
|
||||
Marking blindly a static inline function with Py_ALWAYS_INLINE can result in
|
||||
worse performances (due to increased code size for example). The compiler is
|
||||
usually smarter than the developer for the cost/benefit analysis.
|
||||
|
||||
If Python is :ref:`built in debug mode <debug-build>` (if the :c:macro:`Py_DEBUG`
|
||||
macro is defined), the :c:macro:`Py_ALWAYS_INLINE` macro does nothing.
|
||||
|
||||
It must be specified before the function return type. Usage::
|
||||
|
||||
static inline Py_ALWAYS_INLINE int random(void) { return 4; }
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
.. c:macro:: Py_NO_INLINE
|
||||
|
||||
Disable inlining on a function. For example, it reduces the C stack
|
||||
consumption: useful on LTO+PGO builds which heavily inline code (see
|
||||
:issue:`33720`).
|
||||
|
||||
Corresponds to the ``noinline`` attribute/specification on GCC and MSVC.
|
||||
|
||||
Usage::
|
||||
|
||||
Py_NO_INLINE static int random(void) { return 4; }
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
.. c:macro:: Py_DEPRECATED(version)
|
||||
|
||||
Use this to declare APIs that were deprecated in a specific CPython version.
|
||||
The macro must be placed before the symbol name.
|
||||
|
||||
Example::
|
||||
|
||||
Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);
|
||||
|
||||
.. versionchanged:: 3.8
|
||||
MSVC support was added.
|
||||
|
||||
.. c:macro:: Py_LOCAL(type)
|
||||
|
||||
Declare a function returning the specified *type* using a fast-calling
|
||||
qualifier for functions that are local to the current file.
|
||||
Semantically, this is equivalent to :samp:`static {type}`.
|
||||
|
||||
.. c:macro:: Py_LOCAL_INLINE(type)
|
||||
|
||||
Equivalent to :c:macro:`Py_LOCAL` but additionally requests the function
|
||||
be inlined.
|
||||
|
||||
.. c:macro:: Py_LOCAL_SYMBOL
|
||||
|
||||
Macro used to declare a symbol as local to the shared library (hidden).
|
||||
On supported platforms, it ensures the symbol is not exported.
|
||||
|
||||
On compatible versions of GCC/Clang, it
|
||||
expands to ``__attribute__((visibility("hidden")))``.
|
||||
|
||||
.. c:macro:: Py_EXPORTED_SYMBOL
|
||||
|
||||
|
|
@ -501,16 +522,104 @@ complete listing.
|
|||
This macro is intended for defining CPython's C API itself;
|
||||
extension modules should not use it for their own symbols.
|
||||
|
||||
|
||||
Outdated macros
|
||||
---------------
|
||||
|
||||
The following :term:`soft deprecated` macros have been used to features that
|
||||
have been standardized in C11 (or previous standards).
|
||||
|
||||
.. c:macro:: Py_ALIGNED(num)
|
||||
|
||||
On some GCC-like compilers, specify alignment to *num* bytes.
|
||||
This does nothing on other compilers.
|
||||
|
||||
Use the standard ``alignas`` specifier rather than this macro.
|
||||
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
.. c:macro:: PY_FORMAT_SIZE_T
|
||||
|
||||
The :c:func:`printf` formatting modifier for :c:type:`size_t`.
|
||||
Use ``"z"`` directly instead.
|
||||
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
.. c:macro:: Py_LL(number)
|
||||
Py_ULL(number)
|
||||
|
||||
Use *number* as a ``long long`` or ``unsigned long long`` integer literal,
|
||||
respectively.
|
||||
|
||||
Expands to *number* followed by ``LL`` or ``LLU``, respectively, but will
|
||||
expand to some compiler-specific suffixes on some older compilers.
|
||||
|
||||
Consider using the C99 standard suffixes ``LL`` and ``LLU`` directly.
|
||||
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
.. c:macro:: PY_LONG_LONG
|
||||
PY_INT32_T
|
||||
PY_UINT32_T
|
||||
PY_INT64_T
|
||||
PY_UINT64_T
|
||||
|
||||
Aliases for the types :c:type:`!long long`, :c:type:`!int32_t`,
|
||||
:c:type:`!uint32_t`. :c:type:`!int64_t` and :c:type:`!uint64_t`,
|
||||
respectively.
|
||||
Historically, these types needed compiler-specific extensions.
|
||||
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
.. c:macro:: PY_LLONG_MIN
|
||||
PY_LLONG_MAX
|
||||
PY_ULLONG_MAX
|
||||
PY_SIZE_MAX
|
||||
|
||||
Aliases for the values :c:macro:`!LLONG_MIN`, :c:macro:`!LLONG_MAX`,
|
||||
:c:macro:`!ULLONG_MAX`, and :c:macro:`!SIZE_MAX`, respectively.
|
||||
Use these standard names instead.
|
||||
|
||||
The required header, ``<limits.h>``,
|
||||
:ref:`is included <capi-system-includes>` in ``Python.h``.
|
||||
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
.. c:macro:: Py_MEMCPY(dest, src, n)
|
||||
|
||||
This is an alias to :c:func:`!memcpy`.
|
||||
|
||||
.. soft-deprecated:: 3.14
|
||||
Use :c:func:`!memcpy` directly instead.
|
||||
|
||||
.. c:macro:: Py_UNICODE_SIZE
|
||||
|
||||
Size of the :c:type:`!wchar_t` type.
|
||||
Use ``sizeof(wchar_t)`` or ``WCHAR_WIDTH/8`` instead.
|
||||
|
||||
The required header for the latter, ``<limits.h>``,
|
||||
:ref:`is included <capi-system-includes>` in ``Python.h``.
|
||||
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
.. c:macro:: Py_UNICODE_WIDE
|
||||
|
||||
Defined if ``wchar_t`` can hold a Unicode character (UCS-4).
|
||||
Use ``sizeof(wchar_t) >= 4`` instead
|
||||
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
.. c:macro:: Py_VA_COPY
|
||||
|
||||
This is a :term:`soft deprecated` alias to the C99-standard ``va_copy``
|
||||
function.
|
||||
This is an alias to the C99-standard ``va_copy`` function.
|
||||
|
||||
Historically, this would use a compiler-specific method to copy a ``va_list``.
|
||||
|
||||
.. versionchanged:: 3.6
|
||||
This is now an alias to ``va_copy``.
|
||||
|
||||
.. soft-deprecated:: 3.15
|
||||
|
||||
|
||||
.. _api-objects:
|
||||
|
||||
|
|
|
|||
|
|
@ -74,11 +74,25 @@ List Objects
|
|||
Like :c:func:`PyList_GetItemRef`, but returns a
|
||||
:term:`borrowed reference` instead of a :term:`strong reference`.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, the returned
|
||||
:term:`borrowed reference` may become invalid if another thread modifies
|
||||
the list concurrently. Prefer :c:func:`PyList_GetItemRef`, which returns
|
||||
a :term:`strong reference`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyList_GET_ITEM(PyObject *list, Py_ssize_t i)
|
||||
|
||||
Similar to :c:func:`PyList_GetItem`, but without error checking.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, the returned
|
||||
:term:`borrowed reference` may become invalid if another thread modifies
|
||||
the list concurrently. Prefer :c:func:`PyList_GetItemRef`, which returns
|
||||
a :term:`strong reference`.
|
||||
|
||||
|
||||
.. c:function:: int PyList_SetItem(PyObject *list, Py_ssize_t index, PyObject *item)
|
||||
|
||||
|
|
@ -108,6 +122,14 @@ List Objects
|
|||
is being replaced; any reference in *list* at position *i* will be
|
||||
leaked.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, this macro has no internal
|
||||
synchronization. It is normally only used to fill in new lists where no
|
||||
other thread has a reference to the list. If the list may be shared,
|
||||
use :c:func:`PyList_SetItem` instead, which uses a :term:`per-object
|
||||
lock`.
|
||||
|
||||
|
||||
.. c:function:: int PyList_Insert(PyObject *list, Py_ssize_t index, PyObject *item)
|
||||
|
||||
|
|
@ -138,6 +160,12 @@ List Objects
|
|||
Return ``0`` on success, ``-1`` on failure. Indexing from the end of the
|
||||
list is not supported.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, when *itemlist* is a :class:`list`,
|
||||
both *list* and *itemlist* are locked for the duration of the operation.
|
||||
For other iterables (or ``NULL``), only *list* is locked.
|
||||
|
||||
|
||||
.. c:function:: int PyList_Extend(PyObject *list, PyObject *iterable)
|
||||
|
||||
|
|
@ -150,6 +178,14 @@ List Objects
|
|||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, when *iterable* is a :class:`list`,
|
||||
:class:`set`, :class:`dict`, or dict view, both *list* and *iterable*
|
||||
(or its underlying dict) are locked for the duration of the operation.
|
||||
For other iterables, only *list* is locked; *iterable* may be
|
||||
concurrently modified by another thread.
|
||||
|
||||
|
||||
.. c:function:: int PyList_Clear(PyObject *list)
|
||||
|
||||
|
|
@ -168,6 +204,14 @@ List Objects
|
|||
Sort the items of *list* in place. Return ``0`` on success, ``-1`` on
|
||||
failure. This is equivalent to ``list.sort()``.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, element comparison via
|
||||
:meth:`~object.__lt__` can execute arbitrary Python code, during which
|
||||
the :term:`per-object lock` may be temporarily released. For built-in
|
||||
types (:class:`str`, :class:`int`, :class:`float`), the lock is not
|
||||
released during comparison.
|
||||
|
||||
|
||||
.. c:function:: int PyList_Reverse(PyObject *list)
|
||||
|
||||
|
|
|
|||
|
|
@ -197,12 +197,10 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
|
|||
|
||||
.. c:function:: long PyLong_AS_LONG(PyObject *obj)
|
||||
|
||||
A :term:`soft deprecated` alias.
|
||||
Exactly equivalent to the preferred ``PyLong_AsLong``. In particular,
|
||||
it can fail with :exc:`OverflowError` or another exception.
|
||||
|
||||
.. deprecated:: 3.14
|
||||
The function is soft deprecated.
|
||||
.. soft-deprecated:: 3.14
|
||||
|
||||
.. c:function:: int PyLong_AsInt(PyObject *obj)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@
|
|||
Memory Management
|
||||
*****************
|
||||
|
||||
.. sectionauthor:: Vladimir Marangozov <Vladimir.Marangozov@inrialpes.fr>
|
||||
|
||||
|
||||
|
||||
.. _memoryoverview:
|
||||
|
||||
Overview
|
||||
|
|
@ -208,8 +204,11 @@ The following function sets, modeled after the ANSI C standard, but specifying
|
|||
behavior when requesting zero bytes, are available for allocating and releasing
|
||||
memory from the Python heap.
|
||||
|
||||
The :ref:`default memory allocator <default-memory-allocators>` uses the
|
||||
:ref:`pymalloc memory allocator <pymalloc>`.
|
||||
In the GIL-enabled build (default build) the
|
||||
:ref:`default memory allocator <default-memory-allocators>` uses the
|
||||
:ref:`pymalloc memory allocator <pymalloc>`, whereas in the
|
||||
:term:`free-threaded build`, the default is the
|
||||
:ref:`mimalloc memory allocator <mimalloc>` instead.
|
||||
|
||||
.. warning::
|
||||
|
||||
|
|
@ -219,6 +218,11 @@ The :ref:`default memory allocator <default-memory-allocators>` uses the
|
|||
|
||||
The default allocator is now pymalloc instead of system :c:func:`malloc`.
|
||||
|
||||
.. versionchanged:: 3.13
|
||||
|
||||
In the :term:`free-threaded <free threading>` build, the default allocator
|
||||
is now :ref:`mimalloc <mimalloc>`.
|
||||
|
||||
.. c:function:: void* PyMem_Malloc(size_t n)
|
||||
|
||||
Allocates *n* bytes and returns a pointer of type :c:expr:`void*` to the
|
||||
|
|
@ -344,7 +348,9 @@ memory from the Python heap.
|
|||
the :ref:`Customize Memory Allocators <customize-memory-allocators>` section.
|
||||
|
||||
The :ref:`default object allocator <default-memory-allocators>` uses the
|
||||
:ref:`pymalloc memory allocator <pymalloc>`.
|
||||
:ref:`pymalloc memory allocator <pymalloc>`. In the
|
||||
:term:`free-threaded <free threading>` build, the default is the
|
||||
:ref:`mimalloc memory allocator <mimalloc>` instead.
|
||||
|
||||
.. warning::
|
||||
|
||||
|
|
@ -424,14 +430,16 @@ Default Memory Allocators
|
|||
|
||||
Default memory allocators:
|
||||
|
||||
=============================== ==================== ================== ===================== ====================
|
||||
Configuration Name PyMem_RawMalloc PyMem_Malloc PyObject_Malloc
|
||||
=============================== ==================== ================== ===================== ====================
|
||||
Release build ``"pymalloc"`` ``malloc`` ``pymalloc`` ``pymalloc``
|
||||
Debug build ``"pymalloc_debug"`` ``malloc`` + debug ``pymalloc`` + debug ``pymalloc`` + debug
|
||||
Release build, without pymalloc ``"malloc"`` ``malloc`` ``malloc`` ``malloc``
|
||||
Debug build, without pymalloc ``"malloc_debug"`` ``malloc`` + debug ``malloc`` + debug ``malloc`` + debug
|
||||
=============================== ==================== ================== ===================== ====================
|
||||
=================================== ======================= ==================== ====================== ======================
|
||||
Configuration Name PyMem_RawMalloc PyMem_Malloc PyObject_Malloc
|
||||
=================================== ======================= ==================== ====================== ======================
|
||||
Release build ``"pymalloc"`` ``malloc`` ``pymalloc`` ``pymalloc``
|
||||
Debug build ``"pymalloc_debug"`` ``malloc`` + debug ``pymalloc`` + debug ``pymalloc`` + debug
|
||||
Release build, without pymalloc ``"malloc"`` ``malloc`` ``malloc`` ``malloc``
|
||||
Debug build, without pymalloc ``"malloc_debug"`` ``malloc`` + debug ``malloc`` + debug ``malloc`` + debug
|
||||
Free-threaded build ``"mimalloc"`` ``mimalloc`` ``mimalloc`` ``mimalloc``
|
||||
Free-threaded debug build ``"mimalloc_debug"`` ``mimalloc`` + debug ``mimalloc`` + debug ``mimalloc`` + debug
|
||||
=================================== ======================= ==================== ====================== ======================
|
||||
|
||||
Legend:
|
||||
|
||||
|
|
@ -439,8 +447,7 @@ Legend:
|
|||
* ``malloc``: system allocators from the standard C library, C functions:
|
||||
:c:func:`malloc`, :c:func:`calloc`, :c:func:`realloc` and :c:func:`free`.
|
||||
* ``pymalloc``: :ref:`pymalloc memory allocator <pymalloc>`.
|
||||
* ``mimalloc``: :ref:`mimalloc memory allocator <mimalloc>`. The pymalloc
|
||||
allocator will be used if mimalloc support isn't available.
|
||||
* ``mimalloc``: :ref:`mimalloc memory allocator <mimalloc>`.
|
||||
* "+ debug": with :ref:`debug hooks on the Python memory allocators
|
||||
<pymem-debug-hooks>`.
|
||||
* "Debug build": :ref:`Python build in debug mode <debug-build>`.
|
||||
|
|
@ -737,9 +744,27 @@ The mimalloc allocator
|
|||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
Python supports the mimalloc allocator when the underlying platform support is available.
|
||||
mimalloc "is a general purpose allocator with excellent performance characteristics.
|
||||
Initially developed by Daan Leijen for the runtime systems of the Koka and Lean languages."
|
||||
Python supports the `mimalloc <https://github.com/microsoft/mimalloc/>`__
|
||||
allocator when the underlying platform support is available.
|
||||
mimalloc is a general purpose allocator with excellent performance
|
||||
characteristics, initially developed by Daan Leijen for the runtime systems
|
||||
of the Koka and Lean languages.
|
||||
|
||||
Unlike :ref:`pymalloc <pymalloc>`, which is optimized for small objects (512
|
||||
bytes or fewer), mimalloc handles allocations of any size.
|
||||
|
||||
In the :term:`free-threaded <free threading>` build, mimalloc is the default
|
||||
and **required** allocator for the :c:macro:`PYMEM_DOMAIN_MEM` and
|
||||
:c:macro:`PYMEM_DOMAIN_OBJ` domains. It cannot be disabled in free-threaded
|
||||
builds. The free-threaded build uses per-thread mimalloc heaps, which allows
|
||||
allocation and deallocation to proceed without locking in most cases.
|
||||
|
||||
In the default (non-free-threaded) build, mimalloc is available but not the
|
||||
default allocator. It can be selected at runtime using
|
||||
:envvar:`PYTHONMALLOC`\ ``=mimalloc`` (or ``mimalloc_debug`` to include
|
||||
:ref:`debug hooks <pymem-debug-hooks>`). It can be disabled at build time
|
||||
using the :option:`--without-mimalloc` configure option, but this option
|
||||
cannot be combined with :option:`--disable-gil`.
|
||||
|
||||
tracemalloc C API
|
||||
=================
|
||||
|
|
|
|||
|
|
@ -230,6 +230,9 @@ Feature slots
|
|||
When creating a module, Python checks the value of this slot
|
||||
using :c:func:`PyABIInfo_Check`.
|
||||
|
||||
This slot is required, except for modules created from
|
||||
:c:struct:`PyModuleDef`.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
.. c:macro:: Py_mod_multiple_interpreters
|
||||
|
|
@ -620,9 +623,9 @@ rather than from an extension's :ref:`export hook <extension-export-hook>`.
|
|||
and the :py:class:`~importlib.machinery.ModuleSpec` *spec*.
|
||||
|
||||
The *slots* argument must point to an array of :c:type:`PyModuleDef_Slot`
|
||||
structures, terminated by an entry slot with slot ID of 0
|
||||
structures, terminated by an entry with slot ID of 0
|
||||
(typically written as ``{0}`` or ``{0, NULL}`` in C).
|
||||
The *slots* argument may not be ``NULL``.
|
||||
The array must include a :c:data:`Py_mod_abi` entry.
|
||||
|
||||
The *spec* argument may be any ``ModuleSpec``-like object, as described
|
||||
in :c:macro:`Py_mod_create` documentation.
|
||||
|
|
@ -682,6 +685,12 @@ remove it.
|
|||
Usually, there is only one variable of this type for each extension module
|
||||
defined this way.
|
||||
|
||||
The struct, including all members, is part of the
|
||||
:ref:`Stable ABI <stable-abi>` for non-free-threaded builds (``abi3``).
|
||||
In the Stable ABI for free-threaded builds (``abi3t``),
|
||||
this struct is opaque, and unusable in practice; see :ref:`pymoduledef_slot`
|
||||
for a replacement.
|
||||
|
||||
.. c:member:: PyModuleDef_Base m_base
|
||||
|
||||
Always initialize this member to :c:macro:`PyModuleDef_HEAD_INIT`:
|
||||
|
|
@ -692,6 +701,11 @@ remove it.
|
|||
|
||||
The type of :c:member:`!PyModuleDef.m_base`.
|
||||
|
||||
The struct is part of the :ref:`Stable ABI <stable-abi>` for
|
||||
non-free-threaded builds (``abi3``).
|
||||
In the Stable ABI for Free-Threaded Builds
|
||||
(``abi3t``), this struct is opaque, and unusable in practice.
|
||||
|
||||
.. c:macro:: PyModuleDef_HEAD_INIT
|
||||
|
||||
The required initial value for :c:member:`!PyModuleDef.m_base`.
|
||||
|
|
@ -725,10 +739,11 @@ remove it.
|
|||
|
||||
An array of additional slots, terminated by a ``{0, NULL}`` entry.
|
||||
|
||||
This array may not contain slots corresponding to :c:type:`PyModuleDef`
|
||||
members.
|
||||
For example, you cannot use :c:macro:`Py_mod_name` in :c:member:`!m_slots`;
|
||||
the module name must be given as :c:member:`PyModuleDef.m_name`.
|
||||
If the array contains slots corresponding to :c:type:`PyModuleDef`
|
||||
members, the values must match.
|
||||
For example, if you use :c:macro:`Py_mod_name` in :c:member:`!m_slots`,
|
||||
:c:member:`PyModuleDef.m_name` must be set to the same pointer
|
||||
(not just an equal string).
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
|
|
@ -751,7 +766,12 @@ remove it.
|
|||
.. versionchanged:: 3.9
|
||||
|
||||
:c:member:`m_traverse`, :c:member:`m_clear` and :c:member:`m_free`
|
||||
functions are longer called before the module state is allocated.
|
||||
functions are no longer called before the module state is allocated.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyModuleDef_Type
|
||||
|
||||
The type of ``PyModuleDef`` objects.
|
||||
|
||||
|
||||
.. _moduledef-dynamic:
|
||||
|
|
@ -945,9 +965,7 @@ or code that creates modules dynamically.
|
|||
// PyModule_AddObject() stole a reference to obj:
|
||||
// Py_XDECREF(obj) is not needed here.
|
||||
|
||||
.. deprecated:: 3.13
|
||||
|
||||
:c:func:`PyModule_AddObject` is :term:`soft deprecated`.
|
||||
.. soft-deprecated:: 3.13
|
||||
|
||||
|
||||
.. c:function:: int PyModule_AddIntConstant(PyObject *module, const char *name, long value)
|
||||
|
|
|
|||
|
|
@ -205,6 +205,4 @@ would typically correspond to a Python function.
|
|||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. deprecated:: 3.14
|
||||
|
||||
This function is :term:`soft deprecated`.
|
||||
.. soft-deprecated:: 3.14
|
||||
|
|
|
|||
|
|
@ -363,6 +363,8 @@ Object Protocol
|
|||
representation on success, ``NULL`` on failure. This is the equivalent of the
|
||||
Python expression ``repr(o)``. Called by the :func:`repr` built-in function.
|
||||
|
||||
If argument is ``NULL``, return the string ``'<NULL>'``.
|
||||
|
||||
.. versionchanged:: 3.4
|
||||
This function now includes a debug assertion to help ensure that it
|
||||
does not silently discard an active exception.
|
||||
|
|
@ -377,6 +379,8 @@ Object Protocol
|
|||
a string similar to that returned by :c:func:`PyObject_Repr` in Python 2.
|
||||
Called by the :func:`ascii` built-in function.
|
||||
|
||||
If argument is ``NULL``, return the string ``'<NULL>'``.
|
||||
|
||||
.. index:: string; PyObject_Str (C function)
|
||||
|
||||
|
||||
|
|
@ -387,6 +391,8 @@ Object Protocol
|
|||
Python expression ``str(o)``. Called by the :func:`str` built-in function
|
||||
and, therefore, by the :func:`print` function.
|
||||
|
||||
If argument is ``NULL``, return the string ``'<NULL>'``.
|
||||
|
||||
.. versionchanged:: 3.4
|
||||
This function now includes a debug assertion to help ensure that it
|
||||
does not silently discard an active exception.
|
||||
|
|
@ -402,6 +408,8 @@ Object Protocol
|
|||
a TypeError is raised when *o* is an integer instead of a zero-initialized
|
||||
bytes object.
|
||||
|
||||
If argument is ``NULL``, return the :class:`bytes` object ``b'<NULL>'``.
|
||||
|
||||
|
||||
.. c:function:: int PyObject_IsSubclass(PyObject *derived, PyObject *cls)
|
||||
|
||||
|
|
@ -801,3 +809,20 @@ Object Protocol
|
|||
cannot fail.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
.. c:function:: int PyUnstable_SetImmortal(PyObject *op)
|
||||
|
||||
Marks the object *op* :term:`immortal`. The argument should be uniquely referenced by
|
||||
the calling thread. This is intended to be used for reducing reference counting contention
|
||||
in the :term:`free-threaded build` for objects which are shared across threads.
|
||||
|
||||
This is a one-way process: objects can only be made immortal; they cannot be
|
||||
made mortal once again. Immortal objects do not participate in reference counting
|
||||
and will never be garbage collected. If the object is GC-tracked, it is untracked.
|
||||
|
||||
This function is intended to be used soon after *op* is created, by the code that
|
||||
creates it, such as in the object's :c:member:`~PyTypeObject.tp_new` slot.
|
||||
Returns 1 if the object was made immortal and returns 0 if it was not.
|
||||
This function cannot fail.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
|
|
|||
239
Doc/c-api/profiling.rst
Normal file
239
Doc/c-api/profiling.rst
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
.. highlight:: c
|
||||
|
||||
.. _profiling:
|
||||
|
||||
Profiling and tracing
|
||||
=====================
|
||||
|
||||
The Python interpreter provides some low-level support for attaching profiling
|
||||
and execution tracing facilities. These are used for profiling, debugging, and
|
||||
coverage analysis tools.
|
||||
|
||||
This C interface allows the profiling or tracing code to avoid the overhead of
|
||||
calling through Python-level callable objects, making a direct C function call
|
||||
instead. The essential attributes of the facility have not changed; the
|
||||
interface allows trace functions to be installed per-thread, and the basic
|
||||
events reported to the trace function are the same as had been reported to the
|
||||
Python-level trace functions in previous versions.
|
||||
|
||||
|
||||
.. c:type:: int (*Py_tracefunc)(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg)
|
||||
|
||||
The type of the trace function registered using :c:func:`PyEval_SetProfile` and
|
||||
:c:func:`PyEval_SetTrace`. The first parameter is the object passed to the
|
||||
registration function as *obj*, *frame* is the frame object to which the event
|
||||
pertains, *what* is one of the constants :c:data:`PyTrace_CALL`,
|
||||
:c:data:`PyTrace_EXCEPTION`, :c:data:`PyTrace_LINE`, :c:data:`PyTrace_RETURN`,
|
||||
:c:data:`PyTrace_C_CALL`, :c:data:`PyTrace_C_EXCEPTION`, :c:data:`PyTrace_C_RETURN`,
|
||||
or :c:data:`PyTrace_OPCODE`, and *arg* depends on the value of *what*:
|
||||
|
||||
+-------------------------------+----------------------------------------+
|
||||
| Value of *what* | Meaning of *arg* |
|
||||
+===============================+========================================+
|
||||
| :c:data:`PyTrace_CALL` | Always :c:data:`Py_None`. |
|
||||
+-------------------------------+----------------------------------------+
|
||||
| :c:data:`PyTrace_EXCEPTION` | Exception information as returned by |
|
||||
| | :func:`sys.exc_info`. |
|
||||
+-------------------------------+----------------------------------------+
|
||||
| :c:data:`PyTrace_LINE` | Always :c:data:`Py_None`. |
|
||||
+-------------------------------+----------------------------------------+
|
||||
| :c:data:`PyTrace_RETURN` | Value being returned to the caller, |
|
||||
| | or ``NULL`` if caused by an exception. |
|
||||
+-------------------------------+----------------------------------------+
|
||||
| :c:data:`PyTrace_C_CALL` | Function object being called. |
|
||||
+-------------------------------+----------------------------------------+
|
||||
| :c:data:`PyTrace_C_EXCEPTION` | Function object being called. |
|
||||
+-------------------------------+----------------------------------------+
|
||||
| :c:data:`PyTrace_C_RETURN` | Function object being called. |
|
||||
+-------------------------------+----------------------------------------+
|
||||
| :c:data:`PyTrace_OPCODE` | Always :c:data:`Py_None`. |
|
||||
+-------------------------------+----------------------------------------+
|
||||
|
||||
.. c:var:: int PyTrace_CALL
|
||||
|
||||
The value of the *what* parameter to a :c:type:`Py_tracefunc` function when a new
|
||||
call to a function or method is being reported, or a new entry into a generator.
|
||||
Note that the creation of the iterator for a generator function is not reported
|
||||
as there is no control transfer to the Python bytecode in the corresponding
|
||||
frame.
|
||||
|
||||
|
||||
.. c:var:: int PyTrace_EXCEPTION
|
||||
|
||||
The value of the *what* parameter to a :c:type:`Py_tracefunc` function when an
|
||||
exception has been raised. The callback function is called with this value for
|
||||
*what* when after any bytecode is processed after which the exception becomes
|
||||
set within the frame being executed. The effect of this is that as exception
|
||||
propagation causes the Python stack to unwind, the callback is called upon
|
||||
return to each frame as the exception propagates. Only trace functions receive
|
||||
these events; they are not needed by the profiler.
|
||||
|
||||
|
||||
.. c:var:: int PyTrace_LINE
|
||||
|
||||
The value passed as the *what* parameter to a :c:type:`Py_tracefunc` function
|
||||
(but not a profiling function) when a line-number event is being reported.
|
||||
It may be disabled for a frame by setting :attr:`~frame.f_trace_lines` to
|
||||
*0* on that frame.
|
||||
|
||||
|
||||
.. c:var:: int PyTrace_RETURN
|
||||
|
||||
The value for the *what* parameter to :c:type:`Py_tracefunc` functions when a
|
||||
call is about to return.
|
||||
|
||||
|
||||
.. c:var:: int PyTrace_C_CALL
|
||||
|
||||
The value for the *what* parameter to :c:type:`Py_tracefunc` functions when a C
|
||||
function is about to be called.
|
||||
|
||||
|
||||
.. c:var:: int PyTrace_C_EXCEPTION
|
||||
|
||||
The value for the *what* parameter to :c:type:`Py_tracefunc` functions when a C
|
||||
function has raised an exception.
|
||||
|
||||
|
||||
.. c:var:: int PyTrace_C_RETURN
|
||||
|
||||
The value for the *what* parameter to :c:type:`Py_tracefunc` functions when a C
|
||||
function has returned.
|
||||
|
||||
|
||||
.. c:var:: int PyTrace_OPCODE
|
||||
|
||||
The value for the *what* parameter to :c:type:`Py_tracefunc` functions (but not
|
||||
profiling functions) when a new opcode is about to be executed. This event is
|
||||
not emitted by default: it must be explicitly requested by setting
|
||||
:attr:`~frame.f_trace_opcodes` to *1* on the frame.
|
||||
|
||||
|
||||
.. c:function:: void PyEval_SetProfile(Py_tracefunc func, PyObject *obj)
|
||||
|
||||
Set the profiler function to *func*. The *obj* parameter is passed to the
|
||||
function as its first parameter, and may be any Python object, or ``NULL``. If
|
||||
the profile function needs to maintain state, using a different value for *obj*
|
||||
for each thread provides a convenient and thread-safe place to store it. The
|
||||
profile function is called for all monitored events except :c:data:`PyTrace_LINE`
|
||||
:c:data:`PyTrace_OPCODE` and :c:data:`PyTrace_EXCEPTION`.
|
||||
|
||||
See also the :func:`sys.setprofile` function.
|
||||
|
||||
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 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.
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
|
||||
.. c:function:: void PyEval_SetTrace(Py_tracefunc func, PyObject *obj)
|
||||
|
||||
Set the tracing function to *func*. This is similar to
|
||||
:c:func:`PyEval_SetProfile`, except the tracing function does receive line-number
|
||||
events and per-opcode events, but does not receive any event related to C function
|
||||
objects being called. Any trace function registered using :c:func:`PyEval_SetTrace`
|
||||
will not receive :c:data:`PyTrace_C_CALL`, :c:data:`PyTrace_C_EXCEPTION` or
|
||||
:c:data:`PyTrace_C_RETURN` as a value for the *what* parameter.
|
||||
|
||||
See also the :func:`sys.settrace` function.
|
||||
|
||||
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 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.
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
|
||||
Reference tracing
|
||||
=================
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:type:: int (*PyRefTracer)(PyObject *, int event, void* data)
|
||||
|
||||
The type of the trace function registered using :c:func:`PyRefTracer_SetTracer`.
|
||||
The first parameter is a Python object that has been just created (when **event**
|
||||
is set to :c:data:`PyRefTracer_CREATE`) or about to be destroyed (when **event**
|
||||
is set to :c:data:`PyRefTracer_DESTROY`). The **data** argument is the opaque pointer
|
||||
that was provided when :c:func:`PyRefTracer_SetTracer` was called.
|
||||
|
||||
If a new tracing function is registered replacing the current one, a call to the
|
||||
trace function will be made with the object set to **NULL** and **event** set to
|
||||
:c:data:`PyRefTracer_TRACKER_REMOVED`. This will happen just before the new
|
||||
function is registered.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:var:: int PyRefTracer_CREATE
|
||||
|
||||
The value for the *event* parameter to :c:type:`PyRefTracer` functions when a Python
|
||||
object has been created.
|
||||
|
||||
|
||||
.. c:var:: int PyRefTracer_DESTROY
|
||||
|
||||
The value for the *event* parameter to :c:type:`PyRefTracer` functions when a Python
|
||||
object has been destroyed.
|
||||
|
||||
|
||||
.. c:var:: int PyRefTracer_TRACKER_REMOVED
|
||||
|
||||
The value for the *event* parameter to :c:type:`PyRefTracer` functions when the
|
||||
current tracer is about to be replaced by a new one.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
|
||||
.. c:function:: int PyRefTracer_SetTracer(PyRefTracer tracer, void *data)
|
||||
|
||||
Register a reference tracer function. The function will be called when a new
|
||||
Python object has been created or when an object is going to be destroyed. If
|
||||
**data** is provided it must be an opaque pointer that will be provided when
|
||||
the tracer function is called. Return ``0`` on success. Set an exception and
|
||||
return ``-1`` on error.
|
||||
|
||||
Note 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. A :term:`thread state` will be active
|
||||
every time the tracer function is called.
|
||||
|
||||
There must be an :term:`attached thread state` when calling this function.
|
||||
|
||||
If another tracer function was already registered, the old function will be
|
||||
called with **event** set to :c:data:`PyRefTracer_TRACKER_REMOVED` just before
|
||||
the new function is registered.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:function:: PyRefTracer PyRefTracer_GetTracer(void** data)
|
||||
|
||||
Get the registered reference tracer function and the value of the opaque data
|
||||
pointer that was registered when :c:func:`PyRefTracer_SetTracer` was called.
|
||||
If no tracer was registered this function will return NULL and will set the
|
||||
**data** pointer to NULL.
|
||||
|
||||
There must be an :term:`attached thread state` when calling this function.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
|
@ -109,9 +109,8 @@ Sequence Protocol
|
|||
|
||||
Alias for :c:func:`PySequence_Contains`.
|
||||
|
||||
.. deprecated:: 3.14
|
||||
The function is :term:`soft deprecated` and should no longer be used to
|
||||
write new code.
|
||||
.. soft-deprecated:: 3.14
|
||||
The function should no longer be used to write new code.
|
||||
|
||||
|
||||
.. c:function:: Py_ssize_t PySequence_Index(PyObject *o, PyObject *value)
|
||||
|
|
|
|||
|
|
@ -5,9 +5,6 @@
|
|||
Set Objects
|
||||
-----------
|
||||
|
||||
.. sectionauthor:: Raymond D. Hettinger <python@rcn.com>
|
||||
|
||||
|
||||
.. index::
|
||||
pair: object; set
|
||||
pair: object; frozenset
|
||||
|
|
@ -92,6 +89,11 @@ the constructor functions work with any iterable Python object.
|
|||
actually iterable. The constructor is also useful for copying a set
|
||||
(``c=set(s)``).
|
||||
|
||||
.. note::
|
||||
|
||||
The operation is atomic on :term:`free threading <free-threaded build>`
|
||||
when *iterable* is a :class:`set`, :class:`frozenset`, :class:`dict` or :class:`frozendict`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyFrozenSet_New(PyObject *iterable)
|
||||
|
||||
|
|
@ -100,6 +102,11 @@ the constructor functions work with any iterable Python object.
|
|||
set on success or ``NULL`` on failure. Raise :exc:`TypeError` if *iterable* is
|
||||
not actually iterable.
|
||||
|
||||
.. note::
|
||||
|
||||
The operation is atomic on :term:`free threading <free-threaded build>`
|
||||
when *iterable* is a :class:`set`, :class:`frozenset`, :class:`dict` or :class:`frozendict`.
|
||||
|
||||
|
||||
The following functions and macros are available for instances of :class:`set`
|
||||
or :class:`frozenset` or instances of their subtypes.
|
||||
|
|
@ -127,6 +134,10 @@ or :class:`frozenset` or instances of their subtypes.
|
|||
the *key* is unhashable. Raise :exc:`SystemError` if *anyset* is not a
|
||||
:class:`set`, :class:`frozenset`, or an instance of a subtype.
|
||||
|
||||
.. note::
|
||||
|
||||
The operation is atomic on :term:`free threading <free-threaded build>`
|
||||
when *key* is :class:`str`, :class:`int`, :class:`float`, :class:`bool` or :class:`bytes`.
|
||||
|
||||
.. c:function:: int PySet_Add(PyObject *set, PyObject *key)
|
||||
|
||||
|
|
@ -138,6 +149,12 @@ or :class:`frozenset` or instances of their subtypes.
|
|||
:exc:`SystemError` if *set* is not an instance of :class:`set` or its
|
||||
subtype.
|
||||
|
||||
.. note::
|
||||
|
||||
The operation is atomic on :term:`free threading <free-threaded build>`
|
||||
when *key* is :class:`str`, :class:`int`, :class:`float`, :class:`bool` or :class:`bytes`.
|
||||
|
||||
|
||||
|
||||
The following functions are available for instances of :class:`set` or its
|
||||
subtypes but not for instances of :class:`frozenset` or its subtypes.
|
||||
|
|
@ -152,6 +169,11 @@ subtypes but not for instances of :class:`frozenset` or its subtypes.
|
|||
temporary frozensets. Raise :exc:`SystemError` if *set* is not an
|
||||
instance of :class:`set` or its subtype.
|
||||
|
||||
.. note::
|
||||
|
||||
The operation is atomic on :term:`free threading <free-threaded build>`
|
||||
when *key* is :class:`str`, :class:`int`, :class:`float`, :class:`bool` or :class:`bytes`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PySet_Pop(PyObject *set)
|
||||
|
||||
|
|
@ -167,13 +189,19 @@ subtypes but not for instances of :class:`frozenset` or its subtypes.
|
|||
success. Return ``-1`` and raise :exc:`SystemError` if *set* is not an instance of
|
||||
:class:`set` or its subtype.
|
||||
|
||||
.. note::
|
||||
|
||||
In the :term:`free-threaded build`, the set is emptied before its entries
|
||||
are cleared, so other threads will observe an empty set rather than
|
||||
intermediate states.
|
||||
|
||||
|
||||
Deprecated API
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
.. c:macro:: PySet_MINSIZE
|
||||
|
||||
A :term:`soft deprecated` constant representing the size of an internal
|
||||
A constant representing the size of an internal
|
||||
preallocated table inside :c:type:`PySetObject` instances.
|
||||
|
||||
This is documented solely for completeness, as there are no guarantees
|
||||
|
|
@ -183,3 +211,5 @@ Deprecated API
|
|||
:c:macro:`!PySet_MINSIZE` can be replaced with a small constant like ``8``.
|
||||
|
||||
If looking for the size of a set, use :c:func:`PySet_Size` instead.
|
||||
|
||||
.. soft-deprecated:: 3.14
|
||||
|
|
|
|||
|
|
@ -51,135 +51,212 @@ It is generally intended for specialized, low-level tools like debuggers.
|
|||
Projects that use this API are expected to follow
|
||||
CPython development and spend extra effort adjusting to changes.
|
||||
|
||||
.. _stable-abi:
|
||||
.. _stable-application-binary-interface:
|
||||
|
||||
Stable Application Binary Interface
|
||||
===================================
|
||||
Stable Application Binary Interfaces
|
||||
====================================
|
||||
|
||||
For simplicity, this document talks about *extensions*, but the Limited API
|
||||
and Stable ABI work the same way for all uses of the API – for example,
|
||||
embedding Python.
|
||||
|
||||
.. _limited-c-api:
|
||||
|
||||
Limited C API
|
||||
-------------
|
||||
|
||||
Python 3.2 introduced the *Limited API*, a subset of Python's C API.
|
||||
Extensions that only use the Limited API can be
|
||||
compiled once and be loaded on multiple versions of Python.
|
||||
Contents of the Limited API are :ref:`listed below <limited-api-list>`.
|
||||
|
||||
.. c:macro:: Py_LIMITED_API
|
||||
|
||||
Define this macro before including ``Python.h`` to opt in to only use
|
||||
the Limited API, and to select the Limited API version.
|
||||
|
||||
Define ``Py_LIMITED_API`` to the value of :c:macro:`PY_VERSION_HEX`
|
||||
corresponding to the lowest Python version your extension supports.
|
||||
The extension will be ABI-compatible with all Python 3 releases
|
||||
from the specified one onward, and can use Limited API introduced up to that
|
||||
version.
|
||||
|
||||
Rather than using the ``PY_VERSION_HEX`` macro directly, hardcode a minimum
|
||||
minor version (e.g. ``0x030A0000`` for Python 3.10) for stability when
|
||||
compiling with future Python versions.
|
||||
|
||||
You can also define ``Py_LIMITED_API`` to ``3``. This works the same as
|
||||
``0x03020000`` (Python 3.2, the version that introduced Limited API).
|
||||
|
||||
|
||||
.. _stable-abi:
|
||||
|
||||
Stable ABI
|
||||
----------
|
||||
|
||||
To enable this, Python provides a *Stable ABI*: a set of symbols that will
|
||||
remain ABI-compatible across Python 3.x versions.
|
||||
Python's :dfn:`Stable ABI` allows extensions to be compatible with multiple
|
||||
versions of Python, without recompilation.
|
||||
|
||||
.. note::
|
||||
|
||||
The Stable ABI prevents ABI issues, like linker errors due to missing
|
||||
symbols or data corruption due to changes in structure layouts or function
|
||||
signatures.
|
||||
However, other changes in Python can change the *behavior* of extensions.
|
||||
See Python's Backwards Compatibility Policy (:pep:`387`) for details.
|
||||
For simplicity, this document talks about *extensions*, but Stable ABI
|
||||
works the same way for all uses of the API – for example, embedding Python.
|
||||
|
||||
The Stable ABI contains symbols exposed in the :ref:`Limited API
|
||||
<limited-c-api>`, but also other ones – for example, functions necessary to
|
||||
support older versions of the Limited API.
|
||||
There are two Stable ABIs:
|
||||
|
||||
On Windows, extensions that use the Stable ABI should be linked against
|
||||
- ``abi3``, introduced in Python 3.2, is compatible with
|
||||
**non**-:term:`free-threaded <free-threaded build>` builds of CPython.
|
||||
|
||||
- ``abi3t``, introduced in Python 3.15, is compatible with
|
||||
:term:`free-threaded <free-threaded build>` builds of CPython.
|
||||
It has stricter API limitations than ``abi3``.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
``abi3t`` was added in :pep:`803`
|
||||
|
||||
It is possible for an extension to be compiled for *both* ``abi3`` and
|
||||
``abi3t`` at the same time; the result will be compatible with
|
||||
both free-threaded and non-free-threaded builds of Python.
|
||||
Currently, this has no downsides compared to compiling for ``abi3t`` only.
|
||||
|
||||
Each Stable ABI is versioned using the first two numbers of the Python version.
|
||||
For example, Stable ABI 3.14 corresponds to Python 3.14.
|
||||
An extension compiled for Stable ABI 3.x is ABI-compatible with Python 3.x
|
||||
and above.
|
||||
|
||||
Extensions that target a stable ABI must only use a limited subset of
|
||||
the C API. This subset is known as the :dfn:`Limited API`; its contents
|
||||
are :ref:`listed below <limited-api-list>`.
|
||||
|
||||
On Windows, extensions that use a Stable ABI should be linked against
|
||||
``python3.dll`` rather than a version-specific library such as
|
||||
``python39.dll``.
|
||||
This library only exposes the relevant symbols.
|
||||
|
||||
On some platforms, Python will look for and load shared library files named
|
||||
with the ``abi3`` tag (e.g. ``mymodule.abi3.so``).
|
||||
It does not check if such extensions conform to a Stable ABI.
|
||||
The user (or their packaging tools) need to ensure that, for example,
|
||||
extensions built with the 3.10+ Limited API are not installed for lower
|
||||
with the ``abi3`` or ``abi3t`` tag (for example, ``mymodule.abi3.so``).
|
||||
:term:`Free-threaded <free-threaded build>` interpreters only recognize the
|
||||
``abi3t`` tag, while non-free-threaded ones will prefer ``abi3`` but fall back
|
||||
to ``abi3t``.
|
||||
Thus, extensions compatible with both ABIs should use the ``abi3t`` tag.
|
||||
|
||||
Python does not necessarily check that extensions it loads
|
||||
have compatible ABI.
|
||||
Extension authors are encouraged to add a check using the :c:macro:`Py_mod_abi`
|
||||
slot or the :c:func:`PyABIInfo_Check` function, but the user
|
||||
(or their packaging tool) is ultimately responsible for ensuring that,
|
||||
for example, extensions built for Stable ABI 3.10 are not installed for lower
|
||||
versions of Python.
|
||||
|
||||
All functions in the Stable ABI are present as functions in Python's shared
|
||||
library, not solely as macros. This makes them usable from languages that don't
|
||||
use the C preprocessor.
|
||||
All functions in Stable ABI are present as functions in Python's shared
|
||||
library, not solely as macros.
|
||||
This makes them usable are usable from languages that don't use the C
|
||||
preprocessor, including Python's :py:mod:`ctypes`.
|
||||
|
||||
|
||||
Limited API Scope and Performance
|
||||
---------------------------------
|
||||
.. _abi3-compiling:
|
||||
|
||||
The goal for the Limited API is to allow everything that is possible with the
|
||||
Compiling for Stable ABI
|
||||
------------------------
|
||||
|
||||
.. note::
|
||||
|
||||
Build tools (such as, for example, meson-python, scikit-build-core,
|
||||
or Setuptools) often have a mechanism for setting macros and synchronizing
|
||||
them with extension filenames and other metadata.
|
||||
Prefer using such a mechanism, if it exists, over defining the
|
||||
macros manually.
|
||||
|
||||
The rest of this section is mainly relevant for tool authors, and for
|
||||
people who compile extensions manually.
|
||||
|
||||
.. seealso:: `list of recommended tools`_ in the Python Packaging User Guide
|
||||
|
||||
.. _list of recommended tools: https://packaging.python.org/en/latest/guides/tool-recommendations/#build-backends-for-extension-modules
|
||||
|
||||
To compile for a Stable ABI, define one or both of the following macros
|
||||
to the lowest Python version your extension should support, in
|
||||
:c:macro:`Py_PACK_VERSION` format.
|
||||
Typically, you should choose a specific value rather than the version of
|
||||
the Python headers you are compiling against.
|
||||
|
||||
The macros must be defined before including ``Python.h``.
|
||||
Since :c:macro:`Py_PACK_VERSION` is not available at this point, you
|
||||
will need to use the numeric value directly.
|
||||
For reference, the values for a few recent Python versions are:
|
||||
|
||||
.. version-hex-cheatsheet::
|
||||
|
||||
When one of the macros is defined, ``Python.h`` will only expose API that is
|
||||
compatible with the given Stable ABI -- that is, the
|
||||
:ref:`Limited API <limited-api-list>` plus some definitions that need to be
|
||||
visible to the compiler but should not be used directly.
|
||||
When both are defined, ``Python.h`` will only expose API compatible with
|
||||
both Stable ABIs.
|
||||
|
||||
.. c:macro:: Py_LIMITED_API
|
||||
|
||||
Target ``abi3``, that is,
|
||||
non-:term:`free-threaded builds <free-threaded build>` of CPython.
|
||||
See :ref:`above <abi3-compiling>` for common information.
|
||||
|
||||
.. c:macro:: Py_TARGET_ABI3T
|
||||
|
||||
Target ``abi3t``, that is,
|
||||
:term:`free-threaded builds <free-threaded build>` of CPython.
|
||||
See :ref:`above <abi3-compiling>` for common information.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
Both macros specify a target ABI; the different naming style is due to
|
||||
backwards compatibility.
|
||||
|
||||
.. admonition:: Historical note
|
||||
|
||||
You can also define ``Py_LIMITED_API`` as ``3``. This works the same as
|
||||
``0x03020000`` (Python 3.2, the version that introduced Stable ABI).
|
||||
|
||||
When both are defined, ``Python.h`` may, or may not, redefine
|
||||
:c:macro:`!Py_LIMITED_API` to match :c:macro:`!Py_TARGET_ABI3T`.
|
||||
|
||||
On a :term:`free-threaded build` -- that is, when
|
||||
:c:macro:`Py_GIL_DISABLED` is defined -- :c:macro:`!Py_TARGET_ABI3T`
|
||||
defaults to the value of :c:macro:`!Py_LIMITED_API`.
|
||||
This means that there are two ways to build for both ``abi3`` and ``abi3t``:
|
||||
|
||||
- define both :c:macro:`!Py_LIMITED_API` and :c:macro:`!Py_TARGET_ABI3T`, or
|
||||
- define only :c:macro:`!Py_LIMITED_API` and:
|
||||
|
||||
- on Windows, define :c:macro:`!Py_GIL_DISABLED`;
|
||||
- on other systems, use the headers of free-threaded build of Python.
|
||||
|
||||
|
||||
.. _limited-api-scope-and-performance:
|
||||
|
||||
Stable ABI Scope and Performance
|
||||
--------------------------------
|
||||
|
||||
The goal for Stable ABI is to allow everything that is possible with the
|
||||
full C API, but possibly with a performance penalty.
|
||||
Generally, compatibility with Stable ABI will require some changes to an
|
||||
extension's source code.
|
||||
|
||||
For example, while :c:func:`PyList_GetItem` is available, its “unsafe” macro
|
||||
For example, while :c:func:`PyList_GetItem` is available, its "unsafe" macro
|
||||
variant :c:func:`PyList_GET_ITEM` is not.
|
||||
The macro can be faster because it can rely on version-specific implementation
|
||||
details of the list object.
|
||||
|
||||
Without ``Py_LIMITED_API`` defined, some C API functions are inlined or
|
||||
replaced by macros.
|
||||
Defining ``Py_LIMITED_API`` disables this inlining, allowing stability as
|
||||
For another example, when *not* compiling for Stable ABI, some C API
|
||||
functions are inlined or replaced by macros.
|
||||
Compiling for Stable ABI disables this inlining, allowing stability as
|
||||
Python's data structures are improved, but possibly reducing performance.
|
||||
|
||||
By leaving out the ``Py_LIMITED_API`` definition, it is possible to compile
|
||||
a Limited API extension with a version-specific ABI. This can improve
|
||||
performance for that Python version, but will limit compatibility.
|
||||
Compiling with ``Py_LIMITED_API`` will then yield an extension that can be
|
||||
distributed where a version-specific one is not available – for example,
|
||||
for prereleases of an upcoming Python version.
|
||||
By leaving out the :c:macro:`!Py_LIMITED_API` or :c:macro:`!Py_TARGET_ABI3T`
|
||||
definition, it is possible to compile Stable-ABI-compatible source
|
||||
for a version-specific ABI.
|
||||
A potentially faster version-specific extension can then be distributed
|
||||
alongside a version compiled for Stable ABI -- a slower but more compatible
|
||||
fallback.
|
||||
|
||||
|
||||
Limited API Caveats
|
||||
-------------------
|
||||
.. _limited-api-caveats:
|
||||
|
||||
Note that compiling with ``Py_LIMITED_API`` is *not* a complete guarantee that
|
||||
code conforms to the :ref:`Limited API <limited-c-api>` or the :ref:`Stable ABI
|
||||
<stable-abi>`. ``Py_LIMITED_API`` only covers definitions, but an API also
|
||||
includes other issues, such as expected semantics.
|
||||
Stable ABI Caveats
|
||||
------------------
|
||||
|
||||
One issue that ``Py_LIMITED_API`` does not guard against is calling a function
|
||||
with arguments that are invalid in a lower Python version.
|
||||
Note that compiling for Stable ABI is *not* a complete guarantee that code will
|
||||
be compatible with the expected Python versions.
|
||||
Stable ABI prevents *ABI* issues, like linker errors due to missing
|
||||
symbols or data corruption due to changes in structure layouts or function
|
||||
signatures.
|
||||
However, other changes in Python can change the *behavior* of extensions.
|
||||
|
||||
One issue that the :c:macro:`Py_TARGET_ABI3T` and :c:macro:`Py_LIMITED_API`
|
||||
macros do not guard against is calling a function with arguments that are
|
||||
invalid in a lower Python version.
|
||||
For example, consider a function that starts accepting ``NULL`` for an
|
||||
argument. In Python 3.9, ``NULL`` now selects a default behavior, but in
|
||||
Python 3.8, the argument will be used directly, causing a ``NULL`` dereference
|
||||
and crash. A similar argument works for fields of structs.
|
||||
|
||||
Another issue is that some struct fields are currently not hidden when
|
||||
``Py_LIMITED_API`` is defined, even though they're part of the Limited API.
|
||||
|
||||
For these reasons, we recommend testing an extension with *all* minor Python
|
||||
versions it supports, and preferably to build with the *lowest* such version.
|
||||
versions it supports.
|
||||
|
||||
We also recommend reviewing documentation of all used API to check
|
||||
if it is explicitly part of the Limited API. Even with ``Py_LIMITED_API``
|
||||
defined, a few private declarations are exposed for technical reasons (or
|
||||
even unintentionally, as bugs).
|
||||
|
||||
Also note that the Limited API is not necessarily stable: compiling with
|
||||
``Py_LIMITED_API`` with Python 3.8 means that the extension will
|
||||
run with Python 3.12, but it will not necessarily *compile* with Python 3.12.
|
||||
In particular, parts of the Limited API may be deprecated and removed,
|
||||
provided that the Stable ABI stays stable.
|
||||
Also note that while compiling with ``Py_LIMITED_API`` 3.8 means that the
|
||||
extension should *load* on Python 3.12, and *compile* with Python 3.12,
|
||||
the same source will not necessarily compile with ``Py_LIMITED_API``
|
||||
set to 3.12.
|
||||
In general, parts of the Limited API may be deprecated and removed,
|
||||
provided that Stable ABI stays stable.
|
||||
|
||||
|
||||
.. _stable-abi-platform:
|
||||
|
|
@ -189,12 +266,12 @@ Platform Considerations
|
|||
|
||||
ABI stability depends not only on Python, but also on the compiler used,
|
||||
lower-level libraries and compiler options. For the purposes of
|
||||
the :ref:`Stable ABI <stable-abi>`, these details define a “platform”. They
|
||||
the :ref:`Stable ABIs <stable-abi>`, these details define a “platform”. They
|
||||
usually depend on the OS type and processor architecture
|
||||
|
||||
It is the responsibility of each particular distributor of Python
|
||||
to ensure that all Python versions on a particular platform are built
|
||||
in a way that does not break the Stable ABI.
|
||||
in a way that does not break the Stable ABIs, or the version-specific ABIs.
|
||||
This is the case with Windows and macOS releases from ``python.org`` and many
|
||||
third-party distributors.
|
||||
|
||||
|
|
@ -302,7 +379,7 @@ The full API is described below for advanced use cases.
|
|||
|
||||
.. c:macro:: PyABIInfo_STABLE
|
||||
|
||||
Specifies that the stable ABI is used.
|
||||
Specifies that Stable ABI is used.
|
||||
|
||||
.. c:macro:: PyABIInfo_INTERNAL
|
||||
|
||||
|
|
@ -313,15 +390,22 @@ The full API is described below for advanced use cases.
|
|||
|
||||
.. c:macro:: PyABIInfo_FREETHREADED
|
||||
|
||||
Specifies ABI compatible with free-threading builds of CPython.
|
||||
Specifies ABI compatible with :term:`free-threaded builds
|
||||
<free-threaded build>` of CPython.
|
||||
(That is, ones compiled with :option:`--disable-gil`; with ``t``
|
||||
in :py:data:`sys.abiflags`)
|
||||
|
||||
.. c:macro:: PyABIInfo_GIL
|
||||
|
||||
Specifies ABI compatible with non-free-threading builds of CPython
|
||||
Specifies ABI compatible with non-free-threaded builds of CPython
|
||||
(ones compiled *without* :option:`--disable-gil`).
|
||||
|
||||
.. c:macro:: PyABIInfo_FREETHREADING_AGNOSTIC
|
||||
|
||||
Specifies ABI compatible with both free-threaded and
|
||||
non-free-threaded builds of CPython, that is, both
|
||||
``abi3`` and ``abi3t``.
|
||||
|
||||
.. c:member:: uint32_t build_version
|
||||
|
||||
The version of the Python headers used to build the code, in the format
|
||||
|
|
@ -335,10 +419,11 @@ The full API is described below for advanced use cases.
|
|||
|
||||
The ABI version.
|
||||
|
||||
For the Stable ABI, this field should be the value of
|
||||
:c:macro:`Py_LIMITED_API`
|
||||
(except if :c:macro:`Py_LIMITED_API` is ``3``; use
|
||||
:c:expr:`Py_PACK_VERSION(3, 2)` in that case).
|
||||
For Stable ABI, this field should be the value of
|
||||
:c:macro:`Py_LIMITED_API` or :c:macro:`Py_TARGET_ABI3T`.
|
||||
If both are defined, use the smaller value.
|
||||
(If :c:macro:`Py_LIMITED_API` is ``3``; use
|
||||
:c:expr:`Py_PACK_VERSION(3, 2)` instead of ``3``.)
|
||||
|
||||
Otherwise, it should be set to :c:macro:`PY_VERSION_HEX`.
|
||||
|
||||
|
|
@ -355,12 +440,13 @@ The full API is described below for advanced use cases.
|
|||
.. versionadded:: 3.15
|
||||
|
||||
|
||||
.. _limited-c-api:
|
||||
.. _limited-api-list:
|
||||
|
||||
Contents of Limited API
|
||||
=======================
|
||||
|
||||
|
||||
Currently, the :ref:`Limited API <limited-c-api>` includes the following items:
|
||||
This is the definitive list of :ref:`Limited API <limited-c-api>` for
|
||||
Python |version|:
|
||||
|
||||
.. limited-api-list::
|
||||
|
|
|
|||
|
|
@ -33,6 +33,13 @@ under :ref:`reference counting <countingrefs>`.
|
|||
The members must not be accessed directly; instead use macros such as
|
||||
:c:macro:`Py_REFCNT` and :c:macro:`Py_TYPE`.
|
||||
|
||||
In the :ref:`Stable ABI <stable-abi>` for Free-Threaded Builds (``abi3t``),
|
||||
this struct is opaque; its size and layout may change between
|
||||
Python versions.
|
||||
In Stable ABI for non-free-threaded builds (``abi3``), the
|
||||
:c:member:`!ob_refcnt` and :c:member:`!ob_type` fields are available,
|
||||
but using them directly is discouraged.
|
||||
|
||||
.. c:member:: Py_ssize_t ob_refcnt
|
||||
|
||||
The object's reference count, as returned by :c:macro:`Py_REFCNT`.
|
||||
|
|
@ -48,6 +55,19 @@ under :ref:`reference counting <countingrefs>`.
|
|||
Do not use this field directly; use :c:macro:`Py_TYPE` and
|
||||
:c:func:`Py_SET_TYPE` instead.
|
||||
|
||||
.. c:member:: PyMutex ob_mutex
|
||||
|
||||
A :ref:`per-object lock <per-object-locks>`, present only in the :term:`free-threaded <free threading>`
|
||||
build (when :c:macro:`Py_GIL_DISABLED` is defined).
|
||||
|
||||
This field is **reserved for use by the critical section API**
|
||||
(:c:macro:`Py_BEGIN_CRITICAL_SECTION` / :c:macro:`Py_END_CRITICAL_SECTION`).
|
||||
Do **not** lock it directly with ``PyMutex_Lock``; doing so can cause
|
||||
deadlocks. If you need your own lock, add a separate :c:type:`PyMutex`
|
||||
field to your object struct.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:type:: PyVarObject
|
||||
|
||||
|
|
@ -59,6 +79,19 @@ under :ref:`reference counting <countingrefs>`.
|
|||
instead use macros such as :c:macro:`Py_SIZE`, :c:macro:`Py_REFCNT` and
|
||||
:c:macro:`Py_TYPE`.
|
||||
|
||||
In the :ref:`Stable ABI <stable-abi>` for Free-Threaded Builds (``abi3t``),
|
||||
this struct is opaque; its size and layout may change between
|
||||
Python versions.
|
||||
In Stable ABI for non-free-threaded builds (``abi3``), the
|
||||
:c:member:`!ob_base` and :c:member:`!ob_size` fields are available,
|
||||
but using them directly is discouraged.
|
||||
|
||||
.. c:member:: PyObject ob_base
|
||||
|
||||
Common object header.
|
||||
Typically, this field is not accessed directly; instead
|
||||
:c:type:`!PyVarObject` can be cast to :c:type:`PyObject`.
|
||||
|
||||
.. c:member:: Py_ssize_t ob_size
|
||||
|
||||
A size field, whose contents should be considered an object's internal
|
||||
|
|
@ -410,7 +443,7 @@ There are these calling conventions:
|
|||
|
||||
|
||||
These two constants are not used to indicate the calling convention but the
|
||||
binding when use with methods of classes. These may not be used for functions
|
||||
binding when used with methods of classes. These may not be used for functions
|
||||
defined for modules. At most one of these flags may be set for any given
|
||||
method.
|
||||
|
||||
|
|
|
|||
491
Doc/c-api/subinterpreters.rst
Normal file
491
Doc/c-api/subinterpreters.rst
Normal file
|
|
@ -0,0 +1,491 @@
|
|||
.. highlight:: c
|
||||
|
||||
.. _sub-interpreter-support:
|
||||
|
||||
Multiple interpreters in a Python process
|
||||
=========================================
|
||||
|
||||
While in most uses, you will only embed a single Python interpreter, there
|
||||
are cases where you need to create several independent interpreters in the
|
||||
same process and perhaps even in the same thread. Sub-interpreters allow
|
||||
you to do that.
|
||||
|
||||
The "main" interpreter is the first one created when the runtime initializes.
|
||||
It is usually the only Python interpreter in a process. Unlike sub-interpreters,
|
||||
the main interpreter has unique process-global responsibilities like signal
|
||||
handling. It is also responsible for execution during runtime initialization and
|
||||
is usually the active interpreter during runtime finalization. The
|
||||
:c:func:`PyInterpreterState_Main` function returns a pointer to its state.
|
||||
|
||||
You can switch between sub-interpreters using the :c:func:`PyThreadState_Swap`
|
||||
function. You can create and destroy them using the following functions:
|
||||
|
||||
|
||||
.. c:type:: PyInterpreterConfig
|
||||
|
||||
Structure containing most parameters to configure a sub-interpreter.
|
||||
Its values are used only in :c:func:`Py_NewInterpreterFromConfig` and
|
||||
never modified by the runtime.
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
Structure fields:
|
||||
|
||||
.. c:member:: int use_main_obmalloc
|
||||
|
||||
If this is ``0`` then the sub-interpreter will use its own
|
||||
"object" allocator state.
|
||||
Otherwise it will use (share) the main interpreter's.
|
||||
|
||||
If this is ``0`` then
|
||||
:c:member:`~PyInterpreterConfig.check_multi_interp_extensions`
|
||||
must be ``1`` (non-zero).
|
||||
If this is ``1`` then :c:member:`~PyInterpreterConfig.gil`
|
||||
must not be :c:macro:`PyInterpreterConfig_OWN_GIL`.
|
||||
|
||||
.. c:member:: int allow_fork
|
||||
|
||||
If this is ``0`` then the runtime will not support forking the
|
||||
process in any thread where the sub-interpreter is currently active.
|
||||
Otherwise fork is unrestricted.
|
||||
|
||||
Note that the :mod:`subprocess` module still works
|
||||
when fork is disallowed.
|
||||
|
||||
.. c:member:: int allow_exec
|
||||
|
||||
If this is ``0`` then the runtime will not support replacing the
|
||||
current process via exec (e.g. :func:`os.execv`) in any thread
|
||||
where the sub-interpreter is currently active.
|
||||
Otherwise exec is unrestricted.
|
||||
|
||||
Note that the :mod:`subprocess` module still works
|
||||
when exec is disallowed.
|
||||
|
||||
.. c:member:: int allow_threads
|
||||
|
||||
If this is ``0`` then the sub-interpreter's :mod:`threading` module
|
||||
won't create threads.
|
||||
Otherwise threads are allowed.
|
||||
|
||||
.. c:member:: int allow_daemon_threads
|
||||
|
||||
If this is ``0`` then the sub-interpreter's :mod:`threading` module
|
||||
won't create daemon threads.
|
||||
Otherwise daemon threads are allowed (as long as
|
||||
:c:member:`~PyInterpreterConfig.allow_threads` is non-zero).
|
||||
|
||||
.. c:member:: int check_multi_interp_extensions
|
||||
|
||||
If this is ``0`` then all extension modules may be imported,
|
||||
including legacy (single-phase init) modules,
|
||||
in any thread where the sub-interpreter is currently active.
|
||||
Otherwise only multi-phase init extension modules
|
||||
(see :pep:`489`) may be imported.
|
||||
(Also see :c:macro:`Py_mod_multiple_interpreters`.)
|
||||
|
||||
This must be ``1`` (non-zero) if
|
||||
:c:member:`~PyInterpreterConfig.use_main_obmalloc` is ``0``.
|
||||
|
||||
.. c:member:: int gil
|
||||
|
||||
This determines the operation of the GIL for the sub-interpreter.
|
||||
It may be one of the following:
|
||||
|
||||
.. c:namespace:: NULL
|
||||
|
||||
.. c:macro:: PyInterpreterConfig_DEFAULT_GIL
|
||||
|
||||
Use the default selection (:c:macro:`PyInterpreterConfig_SHARED_GIL`).
|
||||
|
||||
.. c:macro:: PyInterpreterConfig_SHARED_GIL
|
||||
|
||||
Use (share) the main interpreter's GIL.
|
||||
|
||||
.. c:macro:: PyInterpreterConfig_OWN_GIL
|
||||
|
||||
Use the sub-interpreter's own GIL.
|
||||
|
||||
If this is :c:macro:`PyInterpreterConfig_OWN_GIL` then
|
||||
:c:member:`PyInterpreterConfig.use_main_obmalloc` must be ``0``.
|
||||
|
||||
|
||||
.. c:function:: PyStatus Py_NewInterpreterFromConfig(PyThreadState **tstate_p, const PyInterpreterConfig *config)
|
||||
|
||||
.. index::
|
||||
pair: module; builtins
|
||||
pair: module; __main__
|
||||
pair: module; sys
|
||||
single: stdout (in module sys)
|
||||
single: stderr (in module sys)
|
||||
single: stdin (in module sys)
|
||||
|
||||
Create a new sub-interpreter. This is an (almost) totally separate environment
|
||||
for the execution of Python code. In particular, the new interpreter has
|
||||
separate, independent versions of all imported modules, including the
|
||||
fundamental modules :mod:`builtins`, :mod:`__main__` and :mod:`sys`. The
|
||||
table of loaded modules (``sys.modules``) and the module search path
|
||||
(``sys.path``) are also separate. The new environment has no ``sys.argv``
|
||||
variable. It has new standard I/O stream file objects ``sys.stdin``,
|
||||
``sys.stdout`` and ``sys.stderr`` (however these refer to the same underlying
|
||||
file descriptors).
|
||||
|
||||
The given *config* controls the options with which the interpreter
|
||||
is initialized.
|
||||
|
||||
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 <attached thread state>`.
|
||||
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
|
||||
:term:`attached thread state`, which might not exist.
|
||||
|
||||
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 <attached thread state>`.
|
||||
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 <attached thread state>` to the current thread and
|
||||
the previous interpreter's :term:`attached thread state` will remain detached.
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
Sub-interpreters are most effective when isolated from each other,
|
||||
with certain functionality restricted::
|
||||
|
||||
PyInterpreterConfig config = {
|
||||
.use_main_obmalloc = 0,
|
||||
.allow_fork = 0,
|
||||
.allow_exec = 0,
|
||||
.allow_threads = 1,
|
||||
.allow_daemon_threads = 0,
|
||||
.check_multi_interp_extensions = 1,
|
||||
.gil = PyInterpreterConfig_OWN_GIL,
|
||||
};
|
||||
PyThreadState *tstate = NULL;
|
||||
PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config);
|
||||
if (PyStatus_Exception(status)) {
|
||||
Py_ExitStatusException(status);
|
||||
}
|
||||
|
||||
Note that the config is used only briefly and does not get modified.
|
||||
During initialization the config's values are converted into various
|
||||
:c:type:`PyInterpreterState` values. A read-only copy of the config
|
||||
may be stored internally on the :c:type:`PyInterpreterState`.
|
||||
|
||||
.. index::
|
||||
single: Py_FinalizeEx (C function)
|
||||
single: Py_Initialize (C function)
|
||||
|
||||
Extension modules are shared between (sub-)interpreters as follows:
|
||||
|
||||
* For modules using multi-phase initialization,
|
||||
e.g. :c:func:`PyModule_FromDefAndSpec`, a separate module object is
|
||||
created and initialized for each interpreter.
|
||||
Only C-level static and global variables are shared between these
|
||||
module objects.
|
||||
|
||||
* For modules using legacy
|
||||
:ref:`single-phase initialization <single-phase-initialization>`,
|
||||
e.g. :c:func:`PyModule_Create`, the first time a particular extension
|
||||
is imported, it is initialized normally, and a (shallow) copy of its
|
||||
module's dictionary is squirreled away.
|
||||
When the same extension is imported by another (sub-)interpreter, a new
|
||||
module is initialized and filled with the contents of this copy; the
|
||||
extension's ``init`` function is not called.
|
||||
Objects in the module's dictionary thus end up shared across
|
||||
(sub-)interpreters, which might cause unwanted behavior (see
|
||||
`Bugs and caveats`_ below).
|
||||
|
||||
Note that this is different from what happens when an extension is
|
||||
imported after the interpreter has been completely re-initialized by
|
||||
calling :c:func:`Py_FinalizeEx` and :c:func:`Py_Initialize`; in that
|
||||
case, the extension's ``initmodule`` function *is* called again.
|
||||
As with multi-phase initialization, this means that only C-level static
|
||||
and global variables are shared between these modules.
|
||||
|
||||
.. index:: single: close (in module os)
|
||||
|
||||
|
||||
.. c:function:: PyThreadState* Py_NewInterpreter(void)
|
||||
|
||||
.. index::
|
||||
pair: module; builtins
|
||||
pair: module; __main__
|
||||
pair: module; sys
|
||||
single: stdout (in module sys)
|
||||
single: stderr (in module sys)
|
||||
single: stdin (in module sys)
|
||||
|
||||
Create a new sub-interpreter. This is essentially just a wrapper
|
||||
around :c:func:`Py_NewInterpreterFromConfig` with a config that
|
||||
preserves the existing behavior. The result is an unisolated
|
||||
sub-interpreter that shares the main interpreter's GIL, allows
|
||||
fork/exec, allows daemon threads, and allows single-phase init
|
||||
modules.
|
||||
|
||||
|
||||
.. c:function:: void Py_EndInterpreter(PyThreadState *tstate)
|
||||
|
||||
.. index:: single: Py_FinalizeEx (C function)
|
||||
|
||||
Destroy the (sub-)interpreter represented by the given :term:`thread state`.
|
||||
The given thread state must be :term:`attached <attached thread state>`.
|
||||
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.
|
||||
|
||||
|
||||
.. _per-interpreter-gil:
|
||||
|
||||
A per-interpreter GIL
|
||||
---------------------
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
Using :c:func:`Py_NewInterpreterFromConfig` you can create
|
||||
a sub-interpreter that is completely isolated from other interpreters,
|
||||
including having its own GIL. The most important benefit of this
|
||||
isolation is that such an interpreter can execute Python code without
|
||||
being blocked by other interpreters or blocking any others. Thus a
|
||||
single Python process can truly take advantage of multiple CPU cores
|
||||
when running Python code. The isolation also encourages a different
|
||||
approach to concurrency than that of just using threads.
|
||||
(See :pep:`554` and :pep:`684`.)
|
||||
|
||||
Using an isolated interpreter requires vigilance in preserving that
|
||||
isolation. That especially means not sharing any objects or mutable
|
||||
state without guarantees about thread-safety. Even objects that are
|
||||
otherwise immutable (e.g. ``None``, ``(1, 5)``) can't normally be shared
|
||||
because of the refcount. One simple but less-efficient approach around
|
||||
this is to use a global lock around all use of some state (or object).
|
||||
Alternately, effectively immutable objects (like integers or strings)
|
||||
can be made safe in spite of their refcounts by making them :term:`immortal`.
|
||||
In fact, this has been done for the builtin singletons, small integers,
|
||||
and a number of other builtin objects.
|
||||
|
||||
If you preserve isolation then you will have access to proper multi-core
|
||||
computing without the complications that come with free-threading.
|
||||
Failure to preserve isolation will expose you to the full consequences
|
||||
of free-threading, including races and hard-to-debug crashes.
|
||||
|
||||
Aside from that, one of the main challenges of using multiple isolated
|
||||
interpreters is how to communicate between them safely (not break
|
||||
isolation) and efficiently. The runtime and stdlib do not provide
|
||||
any standard approach to this yet. A future stdlib module would help
|
||||
mitigate the effort of preserving isolation and expose effective tools
|
||||
for communicating (and sharing) data between interpreters.
|
||||
|
||||
|
||||
Bugs and caveats
|
||||
----------------
|
||||
|
||||
Because sub-interpreters (and the main interpreter) are part of the same
|
||||
process, the insulation between them isn't perfect --- for example, using
|
||||
low-level file operations like :func:`os.close` they can
|
||||
(accidentally or maliciously) affect each other's open files. Because of the
|
||||
way extensions are shared between (sub-)interpreters, some extensions may not
|
||||
work properly; this is especially likely when using single-phase initialization
|
||||
or (static) global variables.
|
||||
It is possible to insert objects created in one sub-interpreter into
|
||||
a namespace of another (sub-)interpreter; this should be avoided if possible.
|
||||
|
||||
Special care should be taken to avoid sharing user-defined functions,
|
||||
methods, instances or classes between sub-interpreters, since import
|
||||
operations executed by such objects may affect the wrong (sub-)interpreter's
|
||||
dictionary of loaded modules. It is equally important to avoid sharing
|
||||
objects from which the above are reachable.
|
||||
|
||||
Also note that combining this functionality with ``PyGILState_*`` APIs
|
||||
is delicate, because these APIs assume a bijection between Python thread states
|
||||
and OS-level threads, an assumption broken by the presence of sub-interpreters.
|
||||
It is highly recommended that you don't switch sub-interpreters between a pair
|
||||
of matching :c:func:`PyGILState_Ensure` and :c:func:`PyGILState_Release` calls.
|
||||
Furthermore, extensions (such as :mod:`ctypes`) using these APIs to allow calling
|
||||
of Python code from non-Python created threads will probably be broken when using
|
||||
sub-interpreters.
|
||||
|
||||
|
||||
High-level APIs
|
||||
---------------
|
||||
|
||||
.. c:type:: PyInterpreterState
|
||||
|
||||
This data structure represents the state shared by a number of cooperating
|
||||
threads. Threads belonging to the same interpreter share their module
|
||||
administration and a few other internal items. There are no public members in
|
||||
this structure.
|
||||
|
||||
Threads belonging to different interpreters initially share nothing, except
|
||||
process state like available memory, open file descriptors and such. The global
|
||||
interpreter lock is also shared by all threads, regardless of to which
|
||||
interpreter they belong.
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
|
||||
:pep:`684` introduced the possibility
|
||||
of a :ref:`per-interpreter GIL <per-interpreter-gil>`.
|
||||
See :c:func:`Py_NewInterpreterFromConfig`.
|
||||
|
||||
|
||||
.. c:function:: PyInterpreterState* PyInterpreterState_Get(void)
|
||||
|
||||
Get the current interpreter.
|
||||
|
||||
Issue a fatal error if there is no :term:`attached thread state`.
|
||||
It cannot return NULL.
|
||||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
|
||||
.. c:function:: int64_t PyInterpreterState_GetID(PyInterpreterState *interp)
|
||||
|
||||
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 have an :term:`attached thread state`.
|
||||
|
||||
.. versionadded:: 3.7
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyInterpreterState_GetDict(PyInterpreterState *interp)
|
||||
|
||||
Return a dictionary in which interpreter-specific data may be stored.
|
||||
If this function returns ``NULL`` then no exception has been raised and
|
||||
the caller should assume no interpreter-specific dict is available.
|
||||
|
||||
This is not a replacement for :c:func:`PyModule_GetState()`, which
|
||||
extensions should use to store interpreter-specific state information.
|
||||
|
||||
The returned dictionary is borrowed from the interpreter and is valid until
|
||||
interpreter shutdown.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
.. c:type:: PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag)
|
||||
|
||||
Type of a frame evaluation function.
|
||||
|
||||
The *throwflag* parameter is used by the ``throw()`` method of generators:
|
||||
if non-zero, handle the current exception.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
The function now takes a *tstate* parameter.
|
||||
|
||||
.. versionchanged:: 3.11
|
||||
The *frame* parameter changed from ``PyFrameObject*`` to ``_PyInterpreterFrame*``.
|
||||
|
||||
|
||||
.. c:function:: _PyFrameEvalFunction _PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp)
|
||||
|
||||
Get the frame evaluation function.
|
||||
|
||||
See the :pep:`523` "Adding a frame evaluation API to CPython".
|
||||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
|
||||
.. c:function:: void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame)
|
||||
|
||||
Set the frame evaluation function.
|
||||
|
||||
See the :pep:`523` "Adding a frame evaluation API to CPython".
|
||||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
.. c:function:: void _PyInterpreterState_SetEvalFrameAllowSpecialization(PyInterpreterState *interp, int allow_specialization)
|
||||
|
||||
Enables or disables specialization why a custom frame evaluator is in place.
|
||||
|
||||
If *allow_specialization* is non-zero, the adaptive specializer will
|
||||
continue to specialize bytecodes even though a custom eval frame function
|
||||
is set. When *allow_specialization* is zero, setting a custom eval frame
|
||||
disables specialization. The standard interpreter loop will continue to deopt
|
||||
while a frame evaluation API is in place - the frame evaluation function needs
|
||||
to handle the specialized opcodes to take advantage of this.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
.. c:function:: int _PyInterpreterState_IsSpecializationEnabled(PyInterpreterState *interp)
|
||||
|
||||
Return non-zero if adaptive specialization is enabled for the interpreter.
|
||||
Specialization is enabled when no custom eval frame function is set, or
|
||||
when one is set with *allow_specialization* enabled.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
|
||||
Low-level APIs
|
||||
--------------
|
||||
|
||||
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`
|
||||
and sets an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:function:: PyInterpreterState* PyInterpreterState_New()
|
||||
|
||||
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
|
||||
|
||||
|
||||
.. c:function:: void PyInterpreterState_Clear(PyInterpreterState *interp)
|
||||
|
||||
Reset all information in an interpreter state object. There must be
|
||||
an :term:`attached thread state` for the interpreter.
|
||||
|
||||
.. audit-event:: cpython.PyInterpreterState_Clear "" c.PyInterpreterState_Clear
|
||||
|
||||
|
||||
.. c:function:: void PyInterpreterState_Delete(PyInterpreterState *interp)
|
||||
|
||||
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`.
|
||||
|
||||
|
||||
.. _advanced-debugging:
|
||||
|
||||
Advanced debugger support
|
||||
-------------------------
|
||||
|
||||
These functions are only intended to be used by advanced debugging tools.
|
||||
|
||||
|
||||
.. c:function:: PyInterpreterState* PyInterpreterState_Head()
|
||||
|
||||
Return the interpreter state object at the head of the list of all such objects.
|
||||
|
||||
|
||||
.. c:function:: PyInterpreterState* PyInterpreterState_Main()
|
||||
|
||||
Return the main interpreter state object.
|
||||
|
||||
|
||||
.. c:function:: PyInterpreterState* PyInterpreterState_Next(PyInterpreterState *interp)
|
||||
|
||||
Return the next interpreter state object after *interp* from the list of all
|
||||
such objects.
|
||||
|
||||
|
||||
.. c:function:: PyThreadState * PyInterpreterState_ThreadHead(PyInterpreterState *interp)
|
||||
|
||||
Return the pointer to the first :c:type:`PyThreadState` object in the list of
|
||||
threads associated with the interpreter *interp*.
|
||||
|
||||
|
||||
.. c:function:: PyThreadState* PyThreadState_Next(PyThreadState *tstate)
|
||||
|
||||
Return the next thread state object after *tstate* from the list of all such
|
||||
objects belonging to the same :c:type:`PyInterpreterState` object.
|
||||
308
Doc/c-api/synchronization.rst
Normal file
308
Doc/c-api/synchronization.rst
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
.. highlight:: c
|
||||
|
||||
.. _synchronization:
|
||||
|
||||
Synchronization primitives
|
||||
==========================
|
||||
|
||||
The C-API provides a basic mutual exclusion lock.
|
||||
|
||||
.. c:type:: PyMutex
|
||||
|
||||
A mutual exclusion lock. The :c:type:`!PyMutex` should be initialized to
|
||||
zero to represent the unlocked state. For example::
|
||||
|
||||
PyMutex mutex = {0};
|
||||
|
||||
Instances of :c:type:`!PyMutex` should not be copied or moved. Both the
|
||||
contents and address of a :c:type:`!PyMutex` are meaningful, and it must
|
||||
remain at a fixed, writable location in memory.
|
||||
|
||||
.. note::
|
||||
|
||||
A :c:type:`!PyMutex` currently occupies one byte, but the size should be
|
||||
considered unstable. The size may change in future Python releases
|
||||
without a deprecation period.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. c:function:: void PyMutex_Lock(PyMutex *m)
|
||||
|
||||
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 detach the :term:`thread state <attached thread state>` if one exists.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. c:function:: void PyMutex_Unlock(PyMutex *m)
|
||||
|
||||
Unlock mutex *m*. The mutex must be locked --- otherwise, the function will
|
||||
issue a fatal error.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. c:function:: int PyMutex_IsLocked(PyMutex *m)
|
||||
|
||||
Returns non-zero if the mutex *m* is currently locked, zero otherwise.
|
||||
|
||||
.. note::
|
||||
|
||||
This function is intended for use in assertions and debugging only and
|
||||
should not be used to make concurrency control decisions, as the lock
|
||||
state may change immediately after the check.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
.. _python-critical-section-api:
|
||||
|
||||
Python critical section API
|
||||
---------------------------
|
||||
|
||||
The critical section API provides a deadlock avoidance layer on top of
|
||||
per-object locks for :term:`free-threaded <free threading>` CPython. They are
|
||||
intended to replace reliance on the :term:`global interpreter lock`, and are
|
||||
no-ops in versions of Python with the global interpreter lock.
|
||||
|
||||
Critical sections are intended to be used for custom types implemented
|
||||
in C-API extensions. They should generally not be used with built-in types like
|
||||
:class:`list` and :class:`dict` because their public C-APIs
|
||||
already use critical sections internally, with the notable
|
||||
exception of :c:func:`PyDict_Next`, which requires critical section
|
||||
to be acquired externally.
|
||||
|
||||
Critical sections avoid deadlocks by implicitly suspending active critical
|
||||
sections, hence, they do not provide exclusive access such as provided by
|
||||
traditional locks like :c:type:`PyMutex`. When a critical section is started,
|
||||
the per-object lock for the object is acquired. If the code executed inside the
|
||||
critical section calls C-API functions then it can suspend the critical section thereby
|
||||
releasing the per-object lock, so other threads can acquire the per-object lock
|
||||
for the same object.
|
||||
|
||||
Variants that accept :c:type:`PyMutex` pointers rather than Python objects are also
|
||||
available. Use these variants to start a critical section in a situation where
|
||||
there is no :c:type:`PyObject` -- for example, when working with a C type that
|
||||
does not extend or wrap :c:type:`PyObject` but still needs to call into the C
|
||||
API in a manner that might lead to deadlocks.
|
||||
|
||||
The functions and structs used by the macros are exposed for cases
|
||||
where C macros are not available. They should only be used as in the
|
||||
given macro expansions. Note that the sizes and contents of the structures may
|
||||
change in future Python versions.
|
||||
|
||||
.. note::
|
||||
|
||||
Operations that need to lock two objects at once must use
|
||||
:c:macro:`Py_BEGIN_CRITICAL_SECTION2`. You *cannot* use nested critical
|
||||
sections to lock more than one object at once, because the inner critical
|
||||
section may suspend the outer critical sections. This API does not provide
|
||||
a way to lock more than two objects at once.
|
||||
|
||||
Example usage::
|
||||
|
||||
static PyObject *
|
||||
set_field(MyObject *self, PyObject *value)
|
||||
{
|
||||
Py_BEGIN_CRITICAL_SECTION(self);
|
||||
Py_SETREF(self->field, Py_XNewRef(value));
|
||||
Py_END_CRITICAL_SECTION();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
In the above example, :c:macro:`Py_SETREF` calls :c:macro:`Py_DECREF`, which
|
||||
can call arbitrary code through an object's deallocation function. The critical
|
||||
section API avoids potential deadlocks due to reentrancy and lock ordering
|
||||
by allowing the runtime to temporarily suspend the critical section if the
|
||||
code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`.
|
||||
|
||||
.. c:macro:: Py_BEGIN_CRITICAL_SECTION(op)
|
||||
|
||||
Acquires the per-object lock for the object *op* and begins a
|
||||
critical section.
|
||||
|
||||
In the free-threaded build, this macro expands to::
|
||||
|
||||
{
|
||||
PyCriticalSection _py_cs;
|
||||
PyCriticalSection_Begin(&_py_cs, (PyObject*)(op))
|
||||
|
||||
In the default build, this macro expands to ``{``.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. c:macro:: Py_BEGIN_CRITICAL_SECTION_MUTEX(m)
|
||||
|
||||
Locks the mutex *m* and begins a critical section.
|
||||
|
||||
In the free-threaded build, this macro expands to::
|
||||
|
||||
{
|
||||
PyCriticalSection _py_cs;
|
||||
PyCriticalSection_BeginMutex(&_py_cs, m)
|
||||
|
||||
Note that unlike :c:macro:`Py_BEGIN_CRITICAL_SECTION`, there is no cast for
|
||||
the argument of the macro - it must be a :c:type:`PyMutex` pointer.
|
||||
|
||||
On the default build, this macro expands to ``{``.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
.. c:macro:: Py_END_CRITICAL_SECTION()
|
||||
|
||||
Ends the critical section and releases the per-object lock.
|
||||
|
||||
In the free-threaded build, this macro expands to::
|
||||
|
||||
PyCriticalSection_End(&_py_cs);
|
||||
}
|
||||
|
||||
In the default build, this macro expands to ``}``.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. c:macro:: Py_BEGIN_CRITICAL_SECTION2(a, b)
|
||||
|
||||
Acquires the per-object locks for the objects *a* and *b* and begins a
|
||||
critical section. The locks are acquired in a consistent order (lowest
|
||||
address first) to avoid lock ordering deadlocks.
|
||||
|
||||
In the free-threaded build, this macro expands to::
|
||||
|
||||
{
|
||||
PyCriticalSection2 _py_cs2;
|
||||
PyCriticalSection2_Begin(&_py_cs2, (PyObject*)(a), (PyObject*)(b))
|
||||
|
||||
In the default build, this macro expands to ``{``.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. c:macro:: Py_BEGIN_CRITICAL_SECTION2_MUTEX(m1, m2)
|
||||
|
||||
Locks the mutexes *m1* and *m2* and begins a critical section.
|
||||
|
||||
In the free-threaded build, this macro expands to::
|
||||
|
||||
{
|
||||
PyCriticalSection2 _py_cs2;
|
||||
PyCriticalSection2_BeginMutex(&_py_cs2, m1, m2)
|
||||
|
||||
Note that unlike :c:macro:`Py_BEGIN_CRITICAL_SECTION2`, there is no cast for
|
||||
the arguments of the macro - they must be :c:type:`PyMutex` pointers.
|
||||
|
||||
On the default build, this macro expands to ``{``.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
.. c:macro:: Py_END_CRITICAL_SECTION2()
|
||||
|
||||
Ends the critical section and releases the per-object locks.
|
||||
|
||||
In the free-threaded build, this macro expands to::
|
||||
|
||||
PyCriticalSection2_End(&_py_cs2);
|
||||
}
|
||||
|
||||
In the default build, this macro expands to ``}``.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
Legacy locking APIs
|
||||
-------------------
|
||||
|
||||
These APIs are obsolete since Python 3.13 with the introduction of
|
||||
:c:type:`PyMutex`.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
These APIs are now a simple wrapper around ``PyMutex``.
|
||||
|
||||
|
||||
.. c:type:: PyThread_type_lock
|
||||
|
||||
A pointer to a mutual exclusion lock.
|
||||
|
||||
|
||||
.. c:type:: PyLockStatus
|
||||
|
||||
The result of acquiring a lock with a timeout.
|
||||
|
||||
.. c:namespace:: NULL
|
||||
|
||||
.. c:enumerator:: PY_LOCK_FAILURE
|
||||
|
||||
Failed to acquire the lock.
|
||||
|
||||
.. c:enumerator:: PY_LOCK_ACQUIRED
|
||||
|
||||
The lock was successfully acquired.
|
||||
|
||||
.. c:enumerator:: PY_LOCK_INTR
|
||||
|
||||
The lock was interrupted by a signal.
|
||||
|
||||
|
||||
.. c:function:: PyThread_type_lock PyThread_allocate_lock(void)
|
||||
|
||||
Allocate a new lock.
|
||||
|
||||
On success, this function returns a lock; on failure, this
|
||||
function returns ``0`` without an exception set.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
This function now always uses :c:type:`PyMutex`. In prior versions, this
|
||||
would use a lock provided by the operating system.
|
||||
|
||||
|
||||
.. c:function:: void PyThread_free_lock(PyThread_type_lock lock)
|
||||
|
||||
Destroy *lock*. The lock should not be held by any thread when calling
|
||||
this.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:function:: PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock lock, long long microseconds, int intr_flag)
|
||||
|
||||
Acquire *lock* with a timeout.
|
||||
|
||||
This will wait for *microseconds* microseconds to acquire the lock. If the
|
||||
timeout expires, this function returns :c:enumerator:`PY_LOCK_FAILURE`.
|
||||
If *microseconds* is ``-1``, this will wait indefinitely until the lock has
|
||||
been released.
|
||||
|
||||
If *intr_flag* is ``1``, acquiring the lock may be interrupted by a signal,
|
||||
in which case this function returns :c:enumerator:`PY_LOCK_INTR`. Upon
|
||||
interruption, it's generally expected that the caller makes a call to
|
||||
:c:func:`Py_MakePendingCalls` to propagate an exception to Python code.
|
||||
|
||||
If the lock is successfully acquired, this function returns
|
||||
:c:enumerator:`PY_LOCK_ACQUIRED`.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:function:: int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
|
||||
|
||||
Acquire *lock*.
|
||||
|
||||
If *waitflag* is ``1`` and another thread currently holds the lock, this
|
||||
function will wait until the lock can be acquired and will always return
|
||||
``1``.
|
||||
|
||||
If *waitflag* is ``0`` and another thread holds the lock, this function will
|
||||
not wait and instead return ``0``. If the lock is not held by any other
|
||||
thread, then this function will acquire it and return ``1``.
|
||||
|
||||
Unlike :c:func:`PyThread_acquire_lock_timed`, acquiring the lock cannot be
|
||||
interrupted by a signal.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:function:: int PyThread_release_lock(PyThread_type_lock lock)
|
||||
|
||||
Release *lock*. If *lock* is not held, then this function issues a
|
||||
fatal error.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
880
Doc/c-api/threads.rst
Normal file
880
Doc/c-api/threads.rst
Normal file
|
|
@ -0,0 +1,880 @@
|
|||
.. highlight:: c
|
||||
|
||||
.. _threads:
|
||||
|
||||
Thread states and the global interpreter lock
|
||||
=============================================
|
||||
|
||||
.. index::
|
||||
single: global interpreter lock
|
||||
single: interpreter lock
|
||||
single: lock, interpreter
|
||||
|
||||
Unless on a :term:`free-threaded build` of :term:`CPython`,
|
||||
the Python interpreter is generally not 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 a thread before
|
||||
accessing Python objects. Without the lock, even the simplest operations
|
||||
could cause problems in a multi-threaded program: for example, when
|
||||
two threads simultaneously increment the reference count of the same object, the
|
||||
reference count could end up being incremented only once instead of twice.
|
||||
|
||||
As such, only a thread that holds the GIL may operate on Python objects or
|
||||
invoke Python's C API.
|
||||
|
||||
.. index:: single: setswitchinterval (in module sys)
|
||||
|
||||
In order to emulate concurrency, the interpreter regularly tries to switch
|
||||
threads between bytecode instructions (see :func:`sys.setswitchinterval`).
|
||||
This is why locks are also necessary for thread-safety in pure-Python code.
|
||||
|
||||
Additionally, the global interpreter lock is released around blocking I/O
|
||||
operations, such as reading or writing to a file. From the C API, this is done
|
||||
by :ref:`detaching the thread state <detaching-thread-state>`.
|
||||
|
||||
|
||||
.. index::
|
||||
single: PyThreadState (C type)
|
||||
|
||||
The Python interpreter keeps some thread-local information inside
|
||||
a data structure called :c:type:`PyThreadState`, known as a :term:`thread state`.
|
||||
Each thread has a thread-local pointer to a :c:type:`PyThreadState`; a thread state
|
||||
referenced by this pointer is considered to be :term:`attached <attached thread state>`.
|
||||
|
||||
A thread can only have one :term:`attached thread state` at a time. An attached
|
||||
thread state is typically analogous with holding the GIL, except on
|
||||
free-threaded builds. On builds with the GIL enabled, attaching a thread state
|
||||
will block until the GIL can be acquired. However, even on builds with the GIL
|
||||
disabled, it is still required to have an attached thread state, as the interpreter
|
||||
needs to keep track of which threads may access Python objects.
|
||||
|
||||
.. note::
|
||||
|
||||
Even on the free-threaded build, attaching a thread state may block, as the
|
||||
GIL can be re-enabled or threads might be temporarily suspended (such as during
|
||||
a garbage collection).
|
||||
|
||||
Generally, there will always be an attached thread state when using Python's
|
||||
C API, including during embedding and when implementing methods, so it's uncommon
|
||||
to need to set up a thread state on your own. Only in some specific cases, such
|
||||
as in a :c:macro:`Py_BEGIN_ALLOW_THREADS` block or in a fresh thread, will the
|
||||
thread not have an attached thread state.
|
||||
If uncertain, check if :c:func:`PyThreadState_GetUnchecked` returns ``NULL``.
|
||||
|
||||
If it turns out that you do need to create a thread state, call :c:func:`PyThreadState_New`
|
||||
followed by :c:func:`PyThreadState_Swap`, or use the dangerous
|
||||
:c:func:`PyGILState_Ensure` function.
|
||||
|
||||
|
||||
.. _detaching-thread-state:
|
||||
|
||||
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.
|
||||
... Do some blocking I/O operation ...
|
||||
Restore the thread state from the local variable.
|
||||
|
||||
This is so common that a pair of macros exists to simplify it::
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
... Do some blocking I/O operation ...
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
.. index::
|
||||
single: Py_BEGIN_ALLOW_THREADS (C macro)
|
||||
single: Py_END_ALLOW_THREADS (C macro)
|
||||
|
||||
The :c:macro:`Py_BEGIN_ALLOW_THREADS` macro opens a new block and declares a
|
||||
hidden local variable; the :c:macro:`Py_END_ALLOW_THREADS` macro closes the
|
||||
block.
|
||||
|
||||
The block above expands to the following code::
|
||||
|
||||
PyThreadState *_save;
|
||||
|
||||
_save = PyEval_SaveThread();
|
||||
... Do some blocking I/O operation ...
|
||||
PyEval_RestoreThread(_save);
|
||||
|
||||
.. index::
|
||||
single: PyEval_RestoreThread (C function)
|
||||
single: PyEval_SaveThread (C function)
|
||||
|
||||
Here is how these functions work:
|
||||
|
||||
The attached thread state implies that the GIL is held for the interpreter.
|
||||
To detach it, :c:func:`PyEval_SaveThread` is called and the result is stored
|
||||
in a local variable.
|
||||
|
||||
By detaching the thread state, the GIL is released, which allows other threads
|
||||
to attach to the interpreter and execute while the current thread performs
|
||||
blocking I/O. When the I/O operation is complete, the old thread state is
|
||||
reattached by calling :c:func:`PyEval_RestoreThread`, which will wait until
|
||||
the GIL can be acquired.
|
||||
|
||||
.. note::
|
||||
Performing blocking I/O is the most common use case for detaching
|
||||
the thread state, but it is also useful to call it over long-running
|
||||
native code that doesn't need access to Python objects or Python's C API.
|
||||
For example, the standard :mod:`zlib` and :mod:`hashlib` modules detach the
|
||||
:term:`thread state <attached thread state>` when compressing or hashing
|
||||
data.
|
||||
|
||||
On a :term:`free-threaded build`, the :term:`GIL` is usually out of the question,
|
||||
but **detaching the thread state is still required**, because the interpreter
|
||||
periodically needs to block all threads to get a consistent view of Python objects
|
||||
without the risk of race conditions.
|
||||
For example, CPython currently suspends all threads for a short period of time
|
||||
while running the garbage collector.
|
||||
|
||||
.. warning::
|
||||
|
||||
Detaching the thread state can lead to unexpected behavior during interpreter
|
||||
finalization. See :ref:`cautions-regarding-runtime-finalization` for more
|
||||
details.
|
||||
|
||||
|
||||
APIs
|
||||
^^^^
|
||||
|
||||
The following macros are normally used without a trailing semicolon; look for
|
||||
example usage in the Python source distribution.
|
||||
|
||||
.. note::
|
||||
|
||||
These macros are still necessary on the :term:`free-threaded build` to prevent
|
||||
deadlocks.
|
||||
|
||||
.. c:macro:: Py_BEGIN_ALLOW_THREADS
|
||||
|
||||
This macro expands to ``{ PyThreadState *_save; _save = PyEval_SaveThread();``.
|
||||
Note that it contains an opening brace; it must be matched with a following
|
||||
:c:macro:`Py_END_ALLOW_THREADS` macro. See above for further discussion of this
|
||||
macro.
|
||||
|
||||
|
||||
.. c:macro:: Py_END_ALLOW_THREADS
|
||||
|
||||
This macro expands to ``PyEval_RestoreThread(_save); }``. Note that it contains
|
||||
a closing brace; it must be matched with an earlier
|
||||
:c:macro:`Py_BEGIN_ALLOW_THREADS` macro. See above for further discussion of
|
||||
this macro.
|
||||
|
||||
|
||||
.. c:macro:: Py_BLOCK_THREADS
|
||||
|
||||
This macro expands to ``PyEval_RestoreThread(_save);``: it is equivalent to
|
||||
:c:macro:`Py_END_ALLOW_THREADS` without the closing brace.
|
||||
|
||||
|
||||
.. c:macro:: Py_UNBLOCK_THREADS
|
||||
|
||||
This macro expands to ``_save = PyEval_SaveThread();``: it is equivalent to
|
||||
:c:macro:`Py_BEGIN_ALLOW_THREADS` without the opening brace and variable
|
||||
declaration.
|
||||
|
||||
|
||||
Non-Python created threads
|
||||
--------------------------
|
||||
|
||||
When threads are created using the dedicated Python APIs (such as the
|
||||
:mod:`threading` module), a thread state is automatically associated with them,
|
||||
However, when a thread is created from native code (for example, by a
|
||||
third-party library with its own thread management), it doesn't hold an
|
||||
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 new thread state and attaching it.
|
||||
|
||||
The most robust way to do this is through :c:func:`PyThreadState_New` followed
|
||||
by :c:func:`PyThreadState_Swap`.
|
||||
|
||||
.. note::
|
||||
``PyThreadState_New`` requires an argument pointing to the desired
|
||||
interpreter; such a pointer can be acquired via a call to
|
||||
:c:func:`PyInterpreterState_Get` from the code where the thread was
|
||||
created.
|
||||
|
||||
For example::
|
||||
|
||||
/* The return value of PyInterpreterState_Get() from the
|
||||
function that created this thread. */
|
||||
PyInterpreterState *interp = thread_data->interp;
|
||||
|
||||
/* Create a new thread state for the interpreter. It does not start out
|
||||
attached. */
|
||||
PyThreadState *tstate = PyThreadState_New(interp);
|
||||
|
||||
/* Attach the thread state, which will acquire the GIL. */
|
||||
PyThreadState_Swap(tstate);
|
||||
|
||||
/* 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();
|
||||
|
||||
.. warning::
|
||||
|
||||
If the interpreter finalized before ``PyThreadState_Swap`` was called, then
|
||||
``interp`` will be a dangling pointer!
|
||||
|
||||
.. _gilstate:
|
||||
|
||||
Legacy API
|
||||
----------
|
||||
|
||||
Another common pattern to call Python code from a non-Python thread is to use
|
||||
:c:func:`PyGILState_Ensure` followed by a call to :c:func:`PyGILState_Release`.
|
||||
|
||||
These functions do not work well when multiple interpreters exist in the Python
|
||||
process. If no Python interpreter has ever been used in the current thread (which
|
||||
is common for threads created outside Python), ``PyGILState_Ensure`` will create
|
||||
and attach a thread state for the "main" interpreter (the first interpreter in
|
||||
the Python process).
|
||||
|
||||
Additionally, these functions have thread-safety issues during interpreter
|
||||
finalization. Using ``PyGILState_Ensure`` during finalization will likely
|
||||
crash the process.
|
||||
|
||||
Usage of these functions look like such::
|
||||
|
||||
PyGILState_STATE gstate;
|
||||
gstate = PyGILState_Ensure();
|
||||
|
||||
/* Perform Python actions here. */
|
||||
result = CallSomeFunction();
|
||||
/* evaluate result or handle exception */
|
||||
|
||||
/* Release the thread. No Python API allowed beyond this point. */
|
||||
PyGILState_Release(gstate);
|
||||
|
||||
|
||||
.. _fork-and-threads:
|
||||
|
||||
Cautions about fork()
|
||||
---------------------
|
||||
|
||||
Another important thing to note about threads is their behaviour in the face
|
||||
of the C :c:func:`fork` call. On most systems with :c:func:`fork`, after a
|
||||
process forks only the thread that issued the fork will exist. This has a
|
||||
concrete impact both on how locks must be handled and on all stored state
|
||||
in CPython's runtime.
|
||||
|
||||
The fact that only the "current" thread remains
|
||||
means any locks held by other threads will never be released. Python solves
|
||||
this for :func:`os.fork` by acquiring the locks it uses internally before
|
||||
the fork, and releasing them afterwards. In addition, it resets any
|
||||
:ref:`lock-objects` in the child. When extending or embedding Python, there
|
||||
is no way to inform Python of additional (non-Python) locks that need to be
|
||||
acquired before or reset after a fork. OS facilities such as
|
||||
:c:func:`!pthread_atfork` would need to be used to accomplish the same thing.
|
||||
Additionally, when extending or embedding Python, calling :c:func:`fork`
|
||||
directly rather than through :func:`os.fork` (and returning to or calling
|
||||
into Python) may result in a deadlock by one of Python's internal locks
|
||||
being held by a thread that is defunct after the fork.
|
||||
:c:func:`PyOS_AfterFork_Child` tries to reset the necessary locks, but is not
|
||||
always able to.
|
||||
|
||||
The fact that all other threads go away also means that CPython's
|
||||
runtime state there must be cleaned up properly, which :func:`os.fork`
|
||||
does. This means finalizing all other :c:type:`PyThreadState` objects
|
||||
belonging to the current interpreter and all other
|
||||
:c:type:`PyInterpreterState` objects. Due to this and the special
|
||||
nature of the :ref:`"main" interpreter <sub-interpreter-support>`,
|
||||
:c:func:`fork` should only be called in that interpreter's "main"
|
||||
thread, where the CPython global runtime was originally initialized.
|
||||
The only exception is if :c:func:`exec` will be called immediately
|
||||
after.
|
||||
|
||||
|
||||
High-level APIs
|
||||
---------------
|
||||
|
||||
These are the most commonly used types and functions when writing multi-threaded
|
||||
C extensions.
|
||||
|
||||
|
||||
.. c:type:: PyThreadState
|
||||
|
||||
This data structure represents the state of a single thread. The only public
|
||||
data member is:
|
||||
|
||||
.. c:member:: PyInterpreterState *interp
|
||||
|
||||
This thread's interpreter state.
|
||||
|
||||
|
||||
.. c:function:: void PyEval_InitThreads()
|
||||
|
||||
.. index::
|
||||
single: PyEval_AcquireThread()
|
||||
single: PyEval_ReleaseThread()
|
||||
single: PyEval_SaveThread()
|
||||
single: PyEval_RestoreThread()
|
||||
|
||||
Deprecated function which does nothing.
|
||||
|
||||
In Python 3.6 and older, this function created the GIL if it didn't exist.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
The function now does nothing.
|
||||
|
||||
.. versionchanged:: 3.7
|
||||
This function is now called by :c:func:`Py_Initialize()`, so you don't
|
||||
have to call it yourself anymore.
|
||||
|
||||
.. versionchanged:: 3.2
|
||||
This function cannot be called before :c:func:`Py_Initialize()` anymore.
|
||||
|
||||
.. deprecated:: 3.9
|
||||
|
||||
.. index:: pair: module; _thread
|
||||
|
||||
|
||||
.. c:function:: PyThreadState* PyEval_SaveThread()
|
||||
|
||||
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)
|
||||
|
||||
Set the :term:`attached thread state` to *tstate*.
|
||||
The passed :term:`thread state` **should not** be :term:`attached <attached thread state>`,
|
||||
otherwise deadlock ensues. *tstate* will be attached upon returning.
|
||||
|
||||
.. 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
|
||||
:ref:`cautions-regarding-runtime-finalization` for more details.
|
||||
|
||||
.. versionchanged:: 3.14
|
||||
Hangs the current thread, rather than terminating it, if called while the
|
||||
interpreter is finalizing.
|
||||
|
||||
.. c:function:: PyThreadState* PyThreadState_Get()
|
||||
|
||||
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
|
||||
fatal error if it is NULL. The caller is responsible to check if the result
|
||||
is NULL.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
In Python 3.5 to 3.12, the function was private and known as
|
||||
``_PyThreadState_UncheckedGet()``.
|
||||
|
||||
|
||||
.. c:function:: PyThreadState* PyThreadState_Swap(PyThreadState *tstate)
|
||||
|
||||
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.
|
||||
|
||||
|
||||
GIL-state APIs
|
||||
--------------
|
||||
|
||||
The following functions use thread-local storage, and are not compatible
|
||||
with sub-interpreters:
|
||||
|
||||
.. c:type:: PyGILState_STATE
|
||||
|
||||
The type of the value returned by :c:func:`PyGILState_Ensure` and passed to
|
||||
:c:func:`PyGILState_Release`.
|
||||
|
||||
.. c:enumerator:: PyGILState_LOCKED
|
||||
|
||||
The GIL was already held when :c:func:`PyGILState_Ensure` was called.
|
||||
|
||||
.. c:enumerator:: PyGILState_UNLOCKED
|
||||
|
||||
The GIL was not held when :c:func:`PyGILState_Ensure` was called.
|
||||
|
||||
.. 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 :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
|
||||
:c:func:`PyGILState_Release` calls as long as the thread state is restored to
|
||||
its previous state before the Release(). For example, normal usage of the
|
||||
: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 :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, there will be an :term:`attached thread state`
|
||||
and the thread will be able to call arbitrary Python code. Failure is a fatal error.
|
||||
|
||||
.. 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
|
||||
Hangs the current thread, rather than terminating it, if called while the
|
||||
interpreter is finalizing.
|
||||
|
||||
.. c:function:: void PyGILState_Release(PyGILState_STATE)
|
||||
|
||||
Release any resources previously acquired. After this call, Python's state will
|
||||
be the same as it was prior to the corresponding :c:func:`PyGILState_Ensure` call
|
||||
(but generally this state will be unknown to the caller, hence the use of the
|
||||
GILState API).
|
||||
|
||||
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 :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 may return non-``NULL`` even when the :term:`thread state`
|
||||
is detached.
|
||||
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 :term:`GIL` and ``0`` otherwise.
|
||||
This function can be called from any thread at any time.
|
||||
Only if it has had its :term:`thread state <attached 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 :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
|
||||
|
||||
|
||||
Low-level APIs
|
||||
--------------
|
||||
|
||||
.. c:function:: PyThreadState* PyThreadState_New(PyInterpreterState *interp)
|
||||
|
||||
Create a new thread state object belonging to the given interpreter object.
|
||||
An :term:`attached thread state` is not needed.
|
||||
|
||||
.. c:function:: void PyThreadState_Clear(PyThreadState *tstate)
|
||||
|
||||
Reset all information in a :term:`thread state` object. *tstate*
|
||||
must be :term:`attached <attached thread state>`
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
This function now calls the :c:member:`!PyThreadState.on_delete` callback.
|
||||
Previously, that happened in :c:func:`PyThreadState_Delete`.
|
||||
|
||||
.. versionchanged:: 3.13
|
||||
The :c:member:`!PyThreadState.on_delete` callback was removed.
|
||||
|
||||
|
||||
.. c:function:: void PyThreadState_Delete(PyThreadState *tstate)
|
||||
|
||||
Destroy a :term:`thread state` object. *tstate* should not
|
||||
be :term:`attached <attached thread state>` to any thread.
|
||||
*tstate* must have been reset with a previous call to
|
||||
:c:func:`PyThreadState_Clear`.
|
||||
|
||||
|
||||
.. c:function:: void PyThreadState_DeleteCurrent(void)
|
||||
|
||||
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 <attached thread state>` upon
|
||||
returning.
|
||||
|
||||
.. c:function:: PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
|
||||
|
||||
Get the current frame of the Python thread state *tstate*.
|
||||
|
||||
Return a :term:`strong reference`. Return ``NULL`` if no frame is currently
|
||||
executing.
|
||||
|
||||
See also :c:func:`PyEval_GetFrame`.
|
||||
|
||||
*tstate* must not be ``NULL``, and must be :term:`attached <attached thread state>`.
|
||||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
|
||||
.. c:function:: uint64_t PyThreadState_GetID(PyThreadState *tstate)
|
||||
|
||||
Get the unique :term:`thread state` identifier of the Python thread state *tstate*.
|
||||
|
||||
*tstate* must not be ``NULL``, and must be :term:`attached <attached thread state>`.
|
||||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
|
||||
.. c:function:: PyInterpreterState* PyThreadState_GetInterpreter(PyThreadState *tstate)
|
||||
|
||||
Get the interpreter of the Python thread state *tstate*.
|
||||
|
||||
*tstate* must not be ``NULL``, and must be :term:`attached <attached thread state>`.
|
||||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
|
||||
.. c:function:: void PyThreadState_EnterTracing(PyThreadState *tstate)
|
||||
|
||||
Suspend tracing and profiling in the Python thread state *tstate*.
|
||||
|
||||
Resume them using the :c:func:`PyThreadState_LeaveTracing` function.
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
|
||||
.. c:function:: void PyThreadState_LeaveTracing(PyThreadState *tstate)
|
||||
|
||||
Resume tracing and profiling in the Python thread state *tstate* suspended
|
||||
by the :c:func:`PyThreadState_EnterTracing` function.
|
||||
|
||||
See also :c:func:`PyEval_SetTrace` and :c:func:`PyEval_SetProfile`
|
||||
functions.
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
|
||||
.. c:function:: int PyUnstable_ThreadState_SetStackProtection(PyThreadState *tstate, void *stack_start_addr, size_t stack_size)
|
||||
|
||||
Set the stack protection start address and stack protection size
|
||||
of a Python thread state.
|
||||
|
||||
On success, return ``0``.
|
||||
On failure, set an exception and return ``-1``.
|
||||
|
||||
CPython implements :ref:`recursion control <recursion>` for C code by raising
|
||||
:py:exc:`RecursionError` when it notices that the machine execution stack is close
|
||||
to overflow. See for example the :c:func:`Py_EnterRecursiveCall` function.
|
||||
For this, it needs to know the location of the current thread's stack, which it
|
||||
normally gets from the operating system.
|
||||
When the stack is changed, for example using context switching techniques like the
|
||||
Boost library's ``boost::context``, you must call
|
||||
:c:func:`~PyUnstable_ThreadState_SetStackProtection` to inform CPython of the change.
|
||||
|
||||
Call :c:func:`~PyUnstable_ThreadState_SetStackProtection` either before
|
||||
or after changing the stack.
|
||||
Do not call any other Python C API between the call and the stack
|
||||
change.
|
||||
|
||||
See :c:func:`PyUnstable_ThreadState_ResetStackProtection` for undoing this operation.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
|
||||
.. c:function:: void PyUnstable_ThreadState_ResetStackProtection(PyThreadState *tstate)
|
||||
|
||||
Reset the stack protection start address and stack protection size
|
||||
of a Python thread state to the operating system defaults.
|
||||
|
||||
See :c:func:`PyUnstable_ThreadState_SetStackProtection` for an explanation.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyThreadState_GetDict()
|
||||
|
||||
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 :term:`thread state`
|
||||
is :term:`attached <attached thread state>`. If this function returns
|
||||
``NULL``, no exception has been raised and the caller should assume no
|
||||
thread state is attached.
|
||||
|
||||
|
||||
.. c:function:: void PyEval_AcquireThread(PyThreadState *tstate)
|
||||
|
||||
:term:`Attach <attached thread state>` *tstate* to the current thread,
|
||||
which must not be ``NULL`` or already :term:`attached <attached thread state>`.
|
||||
|
||||
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
|
||||
hang the thread until the program exits, even if the thread was not
|
||||
created by Python. Refer to
|
||||
:ref:`cautions-regarding-runtime-finalization` for more details.
|
||||
|
||||
.. versionchanged:: 3.8
|
||||
Updated to be consistent with :c:func:`PyEval_RestoreThread`,
|
||||
:c:func:`Py_END_ALLOW_THREADS`, and :c:func:`PyGILState_Ensure`,
|
||||
and terminate the current thread if called while the interpreter is finalizing.
|
||||
|
||||
.. versionchanged:: 3.14
|
||||
Hangs the current thread, rather than terminating it, if called while the
|
||||
interpreter is finalizing.
|
||||
|
||||
:c:func:`PyEval_RestoreThread` is a higher-level function which is always
|
||||
available (even when threads have not been initialized).
|
||||
|
||||
|
||||
.. c:function:: void PyEval_ReleaseThread(PyThreadState *tstate)
|
||||
|
||||
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
|
||||
available (even when threads have not been initialized).
|
||||
|
||||
|
||||
Asynchronous notifications
|
||||
==========================
|
||||
|
||||
A mechanism is provided to make asynchronous notifications to the main
|
||||
interpreter thread. These notifications take the form of a function
|
||||
pointer and a void pointer argument.
|
||||
|
||||
|
||||
.. c:function:: int Py_AddPendingCall(int (*func)(void *), void *arg)
|
||||
|
||||
Schedule a function to be called from the main interpreter thread. On
|
||||
success, ``0`` is returned and *func* is queued for being called in the
|
||||
main thread. On failure, ``-1`` is returned without setting any exception.
|
||||
|
||||
When successfully queued, *func* will be *eventually* called from the
|
||||
main interpreter thread with the argument *arg*. It will be called
|
||||
asynchronously with respect to normally running Python code, but with
|
||||
both these conditions met:
|
||||
|
||||
* on a :term:`bytecode` boundary;
|
||||
* 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 :term:`thread state <attached thread state>` is detached.
|
||||
|
||||
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.
|
||||
There is no guarantee that *func* will be called as quick as
|
||||
possible. If the main thread is busy executing a system call,
|
||||
*func* won't be called before the system call returns. This
|
||||
function is generally **not** suitable for calling Python code from
|
||||
arbitrary C threads. Instead, use the :ref:`PyGILState API<gilstate>`.
|
||||
|
||||
.. versionadded:: 3.1
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
If this function is called in a subinterpreter, the function *func* is
|
||||
now scheduled to be called from the subinterpreter, rather than being
|
||||
called from the main interpreter. Each subinterpreter now has its own
|
||||
list of scheduled calls.
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
This function now always schedules *func* to be run in the main
|
||||
interpreter.
|
||||
|
||||
|
||||
.. c:function:: int Py_MakePendingCalls(void)
|
||||
|
||||
Execute all pending calls. This is usually executed automatically by the
|
||||
interpreter.
|
||||
|
||||
This function returns ``0`` on success, and returns ``-1`` with an exception
|
||||
set on failure.
|
||||
|
||||
If this is not called in the main thread of the main
|
||||
interpreter, this function does nothing and returns ``0``.
|
||||
The caller must hold an :term:`attached thread state`.
|
||||
|
||||
.. versionadded:: 3.1
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
This function only runs pending calls in the main interpreter.
|
||||
|
||||
|
||||
.. c:function:: int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
|
||||
|
||||
Schedule an exception to be raised asynchronously in a thread.
|
||||
If the thread has a previously scheduled exception, it is overwritten.
|
||||
|
||||
The *id* argument is the thread id of the target thread, as returned by
|
||||
:c:func:`PyThread_get_thread_ident`.
|
||||
*exc* is the class of the exception to be raised, or ``NULL`` to clear
|
||||
the pending exception (if any).
|
||||
|
||||
Return the number of affected thread states.
|
||||
This is normally ``1`` if *id* is found, even when no change was
|
||||
made (the given *exc* was already pending, or *exc* is ``NULL`` but
|
||||
no exception is pending).
|
||||
If the thread id isn't found, return ``0``. This raises no exceptions.
|
||||
|
||||
To prevent naive misuse, you must write your own C extension to call this.
|
||||
This function must be called with an :term:`attached thread state`.
|
||||
This function does not steal any references to *exc*.
|
||||
This function does not necessarily interrupt system calls such as
|
||||
:py:func:`~time.sleep`.
|
||||
|
||||
.. versionchanged:: 3.7
|
||||
The type of the *id* parameter changed from :c:expr:`long` to
|
||||
:c:expr:`unsigned long`.
|
||||
|
||||
|
||||
Operating system thread APIs
|
||||
============================
|
||||
|
||||
.. c:macro:: PYTHREAD_INVALID_THREAD_ID
|
||||
|
||||
Sentinel value for an invalid thread ID.
|
||||
|
||||
This is currently equivalent to ``(unsigned long)-1``.
|
||||
|
||||
|
||||
.. c:function:: unsigned long PyThread_start_new_thread(void (*func)(void *), void *arg)
|
||||
|
||||
Start function *func* in a new thread with argument *arg*.
|
||||
The resulting thread is not intended to be joined.
|
||||
|
||||
*func* must not be ``NULL``, but *arg* may be ``NULL``.
|
||||
|
||||
On success, this function returns the identifier of the new thread; on failure,
|
||||
this returns :c:macro:`PYTHREAD_INVALID_THREAD_ID`.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:function:: unsigned long PyThread_get_thread_ident(void)
|
||||
|
||||
Return the identifier of the current thread, which will never be zero.
|
||||
|
||||
This function cannot fail, and the caller does not need to hold an
|
||||
:term:`attached thread state`.
|
||||
|
||||
.. seealso::
|
||||
:py:func:`threading.get_ident` and :py:attr:`threading.Thread.ident`
|
||||
expose this identifier to Python.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyThread_GetInfo(void)
|
||||
|
||||
Get general information about the current thread in the form of a
|
||||
:ref:`struct sequence <struct-sequence-objects>` object. This information is
|
||||
accessible as :py:attr:`sys.thread_info` in Python.
|
||||
|
||||
On success, this returns a new :term:`strong reference` to the thread
|
||||
information; on failure, this returns ``NULL`` with an exception set.
|
||||
|
||||
The caller must hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:macro:: PY_HAVE_THREAD_NATIVE_ID
|
||||
|
||||
This macro is defined when the system supports native thread IDs.
|
||||
|
||||
|
||||
.. c:function:: unsigned long PyThread_get_thread_native_id(void)
|
||||
|
||||
Get the native identifier of the current thread as it was assigned by the operating
|
||||
system's kernel, which will never be less than zero.
|
||||
|
||||
This function is only available when :c:macro:`PY_HAVE_THREAD_NATIVE_ID` is
|
||||
defined.
|
||||
|
||||
This function cannot fail, and the caller does not need to hold an
|
||||
:term:`attached thread state`.
|
||||
|
||||
.. seealso::
|
||||
:py:func:`threading.get_native_id`
|
||||
|
||||
|
||||
.. c:function:: void PyThread_exit_thread(void)
|
||||
|
||||
Terminate the current thread. This function is generally considered unsafe
|
||||
and should be avoided. It is kept solely for backwards compatibility.
|
||||
|
||||
This function is only safe to call if all functions in the full call
|
||||
stack are written to safely allow it.
|
||||
|
||||
.. warning::
|
||||
|
||||
If the current system uses POSIX threads (also known as "pthreads"),
|
||||
this calls :manpage:`pthread_exit(3)`, which attempts to unwind the stack
|
||||
and call C++ destructors on some libc implementations. However, if a
|
||||
``noexcept`` function is reached, it may terminate the process.
|
||||
Other systems, such as macOS, do unwinding.
|
||||
|
||||
On Windows, this function calls ``_endthreadex()``, which kills the thread
|
||||
without calling C++ destructors.
|
||||
|
||||
In any case, there is a risk of corruption on the thread's stack.
|
||||
|
||||
.. deprecated:: 3.14
|
||||
|
||||
|
||||
.. c:function:: void PyThread_init_thread(void)
|
||||
|
||||
Initialize ``PyThread*`` APIs. Python executes this function automatically,
|
||||
so there's little need to call it from an extension module.
|
||||
|
||||
|
||||
.. c:function:: int PyThread_set_stacksize(size_t size)
|
||||
|
||||
Set the stack size of the current thread to *size* bytes.
|
||||
|
||||
This function returns ``0`` on success, ``-1`` if *size* is invalid, or
|
||||
``-2`` if the system does not support changing the stack size. This function
|
||||
does not set exceptions.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:function:: size_t PyThread_get_stacksize(void)
|
||||
|
||||
Return the stack size of the current thread in bytes, or ``0`` if the system's
|
||||
default stack size is in use.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
155
Doc/c-api/tls.rst
Normal file
155
Doc/c-api/tls.rst
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
.. highlight:: c
|
||||
|
||||
.. _thread-local-storage:
|
||||
|
||||
Thread-local storage support
|
||||
============================
|
||||
|
||||
The Python interpreter provides low-level support for thread-local storage
|
||||
(TLS) which wraps the underlying native TLS implementation to support the
|
||||
Python-level thread-local storage API (:class:`threading.local`). The
|
||||
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.
|
||||
|
||||
A :term:`thread state` does *not* need to be :term:`attached <attached thread state>`
|
||||
when calling these functions; they supply 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.
|
||||
|
||||
.. note::
|
||||
None of these API functions handle memory management on behalf of the
|
||||
:c:expr:`void*` values. You need to allocate and deallocate them yourself.
|
||||
If the :c:expr:`void*` values happen to be :c:expr:`PyObject*`, these
|
||||
functions don't do refcount operations on them either.
|
||||
|
||||
.. _thread-specific-storage-api:
|
||||
|
||||
Thread-specific storage API
|
||||
---------------------------
|
||||
|
||||
The thread-specific storage (TSS) API was introduced to supersede the use of the existing TLS API within the
|
||||
CPython interpreter. This API uses a new type :c:type:`Py_tss_t` instead of
|
||||
:c:expr:`int` to represent thread keys.
|
||||
|
||||
.. versionadded:: 3.7
|
||||
|
||||
.. seealso:: "A New C-API for Thread-Local Storage in CPython" (:pep:`539`)
|
||||
|
||||
|
||||
.. c:type:: Py_tss_t
|
||||
|
||||
This data structure represents the state of a thread key, the definition of
|
||||
which may depend on the underlying TLS implementation, and it has an
|
||||
internal field representing the key's initialization state. There are no
|
||||
public members in this structure.
|
||||
|
||||
When :ref:`Py_LIMITED_API <stable>` is not defined, static allocation of
|
||||
this type by :c:macro:`Py_tss_NEEDS_INIT` is allowed.
|
||||
|
||||
|
||||
.. c:macro:: Py_tss_NEEDS_INIT
|
||||
|
||||
This macro expands to the initializer for :c:type:`Py_tss_t` variables.
|
||||
Note that this macro won't be defined with :ref:`Py_LIMITED_API <stable>`.
|
||||
|
||||
|
||||
Dynamic allocation
|
||||
------------------
|
||||
|
||||
Dynamic allocation of the :c:type:`Py_tss_t`, required in extension modules
|
||||
built with :ref:`Py_LIMITED_API <stable>`, where static allocation of this type
|
||||
is not possible due to its implementation being opaque at build time.
|
||||
|
||||
|
||||
.. c:function:: Py_tss_t* PyThread_tss_alloc()
|
||||
|
||||
Return a value which is the same state as a value initialized with
|
||||
:c:macro:`Py_tss_NEEDS_INIT`, or ``NULL`` in the case of dynamic allocation
|
||||
failure.
|
||||
|
||||
|
||||
.. c:function:: void PyThread_tss_free(Py_tss_t *key)
|
||||
|
||||
Free the given *key* allocated by :c:func:`PyThread_tss_alloc`, after
|
||||
first calling :c:func:`PyThread_tss_delete` to ensure any associated
|
||||
thread locals have been unassigned. This is a no-op if the *key*
|
||||
argument is ``NULL``.
|
||||
|
||||
.. note::
|
||||
A freed key becomes a dangling pointer. You should reset the key to
|
||||
``NULL``.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
The parameter *key* of these functions must not be ``NULL``. Moreover, the
|
||||
behaviors of :c:func:`PyThread_tss_set` and :c:func:`PyThread_tss_get` are
|
||||
undefined if the given :c:type:`Py_tss_t` has not been initialized by
|
||||
:c:func:`PyThread_tss_create`.
|
||||
|
||||
|
||||
.. c:function:: int PyThread_tss_is_created(Py_tss_t *key)
|
||||
|
||||
Return a non-zero value if the given :c:type:`Py_tss_t` has been initialized
|
||||
by :c:func:`PyThread_tss_create`.
|
||||
|
||||
|
||||
.. c:function:: int PyThread_tss_create(Py_tss_t *key)
|
||||
|
||||
Return a zero value on successful initialization of a TSS key. The behavior
|
||||
is undefined if the value pointed to by the *key* argument is not
|
||||
initialized by :c:macro:`Py_tss_NEEDS_INIT`. This function can be called
|
||||
repeatedly on the same key -- calling it on an already initialized key is a
|
||||
no-op and immediately returns success.
|
||||
|
||||
|
||||
.. c:function:: void PyThread_tss_delete(Py_tss_t *key)
|
||||
|
||||
Destroy a TSS key to forget the values associated with the key across all
|
||||
threads, and change the key's initialization state to uninitialized. A
|
||||
destroyed key is able to be initialized again by
|
||||
:c:func:`PyThread_tss_create`. This function can be called repeatedly on
|
||||
the same key -- calling it on an already destroyed key is a no-op.
|
||||
|
||||
|
||||
.. c:function:: int PyThread_tss_set(Py_tss_t *key, void *value)
|
||||
|
||||
Return a zero value to indicate successfully associating a :c:expr:`void*`
|
||||
value with a TSS key in the current thread. Each thread has a distinct
|
||||
mapping of the key to a :c:expr:`void*` value.
|
||||
|
||||
|
||||
.. c:function:: void* PyThread_tss_get(Py_tss_t *key)
|
||||
|
||||
Return the :c:expr:`void*` value associated with a TSS key in the current
|
||||
thread. This returns ``NULL`` if no value is associated with the key in the
|
||||
current thread.
|
||||
|
||||
|
||||
.. _thread-local-storage-api:
|
||||
|
||||
Legacy APIs
|
||||
-----------
|
||||
|
||||
.. deprecated:: 3.7
|
||||
This API is superseded by the
|
||||
:ref:`thread-specific storage (TSS) API <thread-specific-storage-api>`.
|
||||
|
||||
.. note::
|
||||
This version of the API does not support platforms where the native TLS key
|
||||
is defined in a way that cannot be safely cast to ``int``. On such platforms,
|
||||
:c:func:`PyThread_create_key` will return immediately with a failure status,
|
||||
and the other TLS functions will all be no-ops on such platforms.
|
||||
|
||||
Due to the compatibility problem noted above, this version of the API should not
|
||||
be used in new code.
|
||||
|
||||
.. c:function:: int PyThread_create_key()
|
||||
.. c:function:: void PyThread_delete_key(int key)
|
||||
.. c:function:: int PyThread_set_key_value(int key, void *value)
|
||||
.. c:function:: void* PyThread_get_key_value(int key)
|
||||
.. c:function:: void PyThread_delete_key_value(int key)
|
||||
.. c:function:: void PyThread_ReInitTLS()
|
||||
|
|
@ -99,7 +99,8 @@ Tuple Objects
|
|||
|
||||
Insert a reference to object *o* at position *pos* of the tuple pointed to by
|
||||
*p*. Return ``0`` on success. If *pos* is out of bounds, return ``-1``
|
||||
and set an :exc:`IndexError` exception.
|
||||
and set an :exc:`IndexError` exception. This function should only be used to fill in brand new tuples;
|
||||
using it on an existing tuple is thread-unsafe.
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
@ -110,7 +111,7 @@ Tuple Objects
|
|||
.. c:function:: void PyTuple_SET_ITEM(PyObject *p, Py_ssize_t pos, PyObject *o)
|
||||
|
||||
Like :c:func:`PyTuple_SetItem`, but does no error checking, and should *only* be
|
||||
used to fill in brand new tuples.
|
||||
used to fill in brand new tuples, using it on an existing tuple is thread-unsafe.
|
||||
|
||||
Bounds checking is performed as an assertion if Python is built in
|
||||
:ref:`debug mode <debug-build>` or :option:`with assertions <--with-assertions>`.
|
||||
|
|
@ -236,6 +237,8 @@ type.
|
|||
.. c:function:: PyObject* PyStructSequence_GetItem(PyObject *p, Py_ssize_t pos)
|
||||
|
||||
Return the object at position *pos* in the struct sequence pointed to by *p*.
|
||||
The returned reference is borrowed from the struct sequence *p*
|
||||
(that is: it is only valid as long as you hold a reference to *p*).
|
||||
|
||||
Bounds checking is performed as an assertion if Python is built in
|
||||
:ref:`debug mode <debug-build>` or :option:`with assertions <--with-assertions>`.
|
||||
|
|
|
|||
|
|
@ -274,6 +274,10 @@ Type Objects
|
|||
Return the module object associated with the given type when the type was
|
||||
created using :c:func:`PyType_FromModuleAndSpec`.
|
||||
|
||||
The returned reference is :term:`borrowed <borrowed reference>` from *type*,
|
||||
and will be valid as long as you hold a reference to *type*.
|
||||
Do not release it with :c:func:`Py_DECREF` or similar.
|
||||
|
||||
If no module is associated with the given type, sets :py:class:`TypeError`
|
||||
and returns ``NULL``.
|
||||
|
||||
|
|
|
|||
|
|
@ -1391,8 +1391,8 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. versionchanged:: 3.9
|
||||
|
||||
Renamed to the current name, without the leading underscore.
|
||||
The old provisional name is :term:`soft deprecated`.
|
||||
Renamed to the current name, without the leading underscore.
|
||||
The old provisional name is :term:`soft deprecated`.
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
|
||||
|
|
@ -1499,6 +1499,54 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
It will be removed in a future version of CPython
|
||||
|
||||
|
||||
.. c:macro:: Py_TPFLAGS_HAVE_VERSION_TAG
|
||||
|
||||
This macro does nothing.
|
||||
Historically, this would indicate that the
|
||||
:c:member:`~PyTypeObject.tp_version_tag` field was available and
|
||||
initialized.
|
||||
|
||||
.. soft-deprecated:: 3.13
|
||||
|
||||
|
||||
.. c:macro:: Py_TPFLAGS_INLINE_VALUES
|
||||
|
||||
This bit indicates that instances of this type will have an "inline values"
|
||||
array (containing the object's attributes) placed directly after the end
|
||||
of the object.
|
||||
|
||||
This requires that :c:macro:`Py_TPFLAGS_HAVE_GC` is set.
|
||||
|
||||
**Inheritance:**
|
||||
|
||||
This flag is not inherited.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:macro:: Py_TPFLAGS_IS_ABSTRACT
|
||||
|
||||
This bit indicates that this is an abstract type and therefore cannot
|
||||
be instantiated.
|
||||
|
||||
**Inheritance:**
|
||||
|
||||
This flag is not inherited.
|
||||
|
||||
.. seealso::
|
||||
:mod:`abc`
|
||||
|
||||
|
||||
.. c:macro:: Py_TPFLAGS_HAVE_STACKLESS_EXTENSION
|
||||
|
||||
Internal. Do not set or unset this flag.
|
||||
Historically, this was a reserved flag for use in Stackless Python.
|
||||
|
||||
.. warning::
|
||||
This flag is present in header files, but is not be used.
|
||||
This may be removed in a future version of CPython.
|
||||
|
||||
|
||||
.. c:member:: const char* PyTypeObject.tp_doc
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_doc
|
||||
|
|
@ -1517,93 +1565,9 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
.. corresponding-type-slot:: Py_tp_traverse
|
||||
|
||||
An optional pointer to a traversal function for the garbage collector. This is
|
||||
only used if the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit is set. The signature is::
|
||||
only used if the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit is set.
|
||||
|
||||
int tp_traverse(PyObject *self, visitproc visit, void *arg);
|
||||
|
||||
More information about Python's garbage collection scheme can be found
|
||||
in section :ref:`supporting-cycle-detection`.
|
||||
|
||||
The :c:member:`~PyTypeObject.tp_traverse` pointer is used by the garbage collector to detect
|
||||
reference cycles. A typical implementation of a :c:member:`~PyTypeObject.tp_traverse` function
|
||||
simply calls :c:func:`Py_VISIT` on each of the instance's members that are Python
|
||||
objects that the instance owns. For example, this is function :c:func:`!local_traverse` from the
|
||||
:mod:`!_thread` extension module::
|
||||
|
||||
static int
|
||||
local_traverse(PyObject *op, visitproc visit, void *arg)
|
||||
{
|
||||
localobject *self = (localobject *) op;
|
||||
Py_VISIT(self->args);
|
||||
Py_VISIT(self->kw);
|
||||
Py_VISIT(self->dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Note that :c:func:`Py_VISIT` is called only on those members that can participate
|
||||
in reference cycles. Although there is also a ``self->key`` member, it can only
|
||||
be ``NULL`` or a Python string and therefore cannot be part of a reference cycle.
|
||||
|
||||
On the other hand, even if you know a member can never be part of a cycle, as a
|
||||
debugging aid you may want to visit it anyway just so the :mod:`gc` module's
|
||||
:func:`~gc.get_referents` function will include it.
|
||||
|
||||
Heap types (:c:macro:`Py_TPFLAGS_HEAPTYPE`) must visit their type with::
|
||||
|
||||
Py_VISIT(Py_TYPE(self));
|
||||
|
||||
It is only needed since Python 3.9. To support Python 3.8 and older, this
|
||||
line must be conditional::
|
||||
|
||||
#if PY_VERSION_HEX >= 0x03090000
|
||||
Py_VISIT(Py_TYPE(self));
|
||||
#endif
|
||||
|
||||
If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the
|
||||
:c:member:`~PyTypeObject.tp_flags` field, the traverse function must call
|
||||
:c:func:`PyObject_VisitManagedDict` like this::
|
||||
|
||||
PyObject_VisitManagedDict((PyObject*)self, visit, arg);
|
||||
|
||||
.. warning::
|
||||
When implementing :c:member:`~PyTypeObject.tp_traverse`, only the
|
||||
members that the instance *owns* (by having :term:`strong references
|
||||
<strong reference>` to them) must be
|
||||
visited. For instance, if an object supports weak references via the
|
||||
:c:member:`~PyTypeObject.tp_weaklist` slot, the pointer supporting
|
||||
the linked list (what *tp_weaklist* points to) must **not** be
|
||||
visited as the instance does not directly own the weak references to itself
|
||||
(the weakreference list is there to support the weak reference machinery,
|
||||
but the instance has no strong reference to the elements inside it, as they
|
||||
are allowed to be removed even if the instance is still alive).
|
||||
|
||||
.. warning::
|
||||
The traversal function must not have any side effects. It must not
|
||||
modify the reference counts of any Python objects nor create or destroy
|
||||
any Python objects.
|
||||
|
||||
Note that :c:func:`Py_VISIT` requires the *visit* and *arg* parameters to
|
||||
:c:func:`!local_traverse` to have these specific names; don't name them just
|
||||
anything.
|
||||
|
||||
Instances of :ref:`heap-allocated types <heap-types>` hold a reference to
|
||||
their type. Their traversal function must therefore either visit
|
||||
:c:func:`Py_TYPE(self) <Py_TYPE>`, or delegate this responsibility by
|
||||
calling ``tp_traverse`` of another heap-allocated type (such as a
|
||||
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
|
||||
``tp_traverse``. In earlier versions of Python, due to
|
||||
`bug 40217 <https://bugs.python.org/issue40217>`_, doing this
|
||||
may lead to crashes in subclasses.
|
||||
See :ref:`gc-traversal` for documentation.
|
||||
|
||||
**Inheritance:**
|
||||
|
||||
|
|
@ -2632,9 +2596,6 @@ This is done by filling a :c:type:`PyType_Spec` structure and calling
|
|||
Number Object Structures
|
||||
------------------------
|
||||
|
||||
.. sectionauthor:: Amaury Forgeot d'Arc
|
||||
|
||||
|
||||
.. c:type:: PyNumberMethods
|
||||
|
||||
This structure holds pointers to the functions which an object uses to
|
||||
|
|
@ -2852,9 +2813,6 @@ Number Object Structures
|
|||
Mapping Object Structures
|
||||
-------------------------
|
||||
|
||||
.. sectionauthor:: Amaury Forgeot d'Arc
|
||||
|
||||
|
||||
.. c:type:: PyMappingMethods
|
||||
|
||||
This structure holds pointers to the functions which an object uses to
|
||||
|
|
@ -2895,9 +2853,6 @@ Mapping Object Structures
|
|||
Sequence Object Structures
|
||||
--------------------------
|
||||
|
||||
.. sectionauthor:: Amaury Forgeot d'Arc
|
||||
|
||||
|
||||
.. c:type:: PySequenceMethods
|
||||
|
||||
This structure holds pointers to the functions which an object uses to
|
||||
|
|
@ -2991,10 +2946,6 @@ Sequence Object Structures
|
|||
Buffer Object Structures
|
||||
------------------------
|
||||
|
||||
.. sectionauthor:: Greg J. Stein <greg@lyra.org>
|
||||
.. sectionauthor:: Benjamin Peterson
|
||||
.. sectionauthor:: Stefan Krah
|
||||
|
||||
.. c:type:: PyBufferProcs
|
||||
|
||||
This structure holds pointers to the functions required by the
|
||||
|
|
@ -3024,6 +2975,24 @@ Buffer Object Structures
|
|||
|
||||
(5) Return ``0``.
|
||||
|
||||
**Thread safety:**
|
||||
|
||||
In the :term:`free-threaded build`, implementations must ensure:
|
||||
|
||||
* The export counter increment in step (3) is atomic.
|
||||
|
||||
* The underlying buffer data remains valid and at a stable memory
|
||||
location for the lifetime of all exports.
|
||||
|
||||
* For objects that support resizing or reallocation (such as
|
||||
:class:`bytearray`), the export counter is checked atomically before
|
||||
such operations, and :exc:`BufferError` is raised if exports exist.
|
||||
|
||||
* The function is safe to call concurrently from multiple threads.
|
||||
|
||||
See also :ref:`thread-safety-memoryview` for the Python-level
|
||||
thread safety guarantees of :class:`memoryview` objects.
|
||||
|
||||
If *exporter* is part of a chain or tree of buffer providers, two main
|
||||
schemes can be used:
|
||||
|
||||
|
|
@ -3069,6 +3038,16 @@ Buffer Object Structures
|
|||
|
||||
(2) If the counter is ``0``, free all memory associated with *view*.
|
||||
|
||||
**Thread safety:**
|
||||
|
||||
In the :term:`free-threaded build`:
|
||||
|
||||
* The export counter decrement in step (1) must be atomic.
|
||||
|
||||
* Resource cleanup when the counter reaches zero must be done atomically,
|
||||
as the final release may race with concurrent releases from other
|
||||
threads and dellocation must only happen once.
|
||||
|
||||
The exporter MUST use the :c:member:`~Py_buffer.internal` field to keep
|
||||
track of buffer-specific resources. This field is guaranteed to remain
|
||||
constant, while a consumer MAY pass a copy of the original buffer as the
|
||||
|
|
@ -3090,8 +3069,6 @@ Buffer Object Structures
|
|||
Async Object Structures
|
||||
-----------------------
|
||||
|
||||
.. sectionauthor:: Yury Selivanov <yselivanov@sprymix.com>
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
.. c:type:: PyAsyncMethods
|
||||
|
|
|
|||
|
|
@ -5,9 +5,6 @@
|
|||
Unicode Objects and Codecs
|
||||
--------------------------
|
||||
|
||||
.. sectionauthor:: Marc-André Lemburg <mal@lemburg.com>
|
||||
.. sectionauthor:: Georg Brandl <georg@python.org>
|
||||
|
||||
Unicode Objects
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
@ -1858,8 +1855,6 @@ object.
|
|||
On success, return ``0``.
|
||||
On error, set an exception, leave the writer unchanged, and return ``-1``.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
.. c:function:: int PyUnicodeWriter_WriteWideChar(PyUnicodeWriter *writer, const wchar_t *str, Py_ssize_t size)
|
||||
|
||||
Write the wide string *str* into *writer*.
|
||||
|
|
@ -1870,7 +1865,7 @@ object.
|
|||
On success, return ``0``.
|
||||
On error, set an exception, leave the writer unchanged, and return ``-1``.
|
||||
|
||||
.. c:function:: int PyUnicodeWriter_WriteUCS4(PyUnicodeWriter *writer, Py_UCS4 *str, Py_ssize_t size)
|
||||
.. c:function:: int PyUnicodeWriter_WriteUCS4(PyUnicodeWriter *writer, const Py_UCS4 *str, Py_ssize_t size)
|
||||
|
||||
Writer the UCS4 string *str* into *writer*.
|
||||
|
||||
|
|
@ -1886,13 +1881,23 @@ object.
|
|||
On success, return ``0``.
|
||||
On error, set an exception, leave the writer unchanged, and return ``-1``.
|
||||
|
||||
To write a :class:`str` subclass which overrides the :meth:`~object.__str__`
|
||||
method, :c:func:`PyUnicode_FromObject` can be used to get the original
|
||||
string.
|
||||
|
||||
.. c:function:: int PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj)
|
||||
|
||||
Call :c:func:`PyObject_Repr` on *obj* and write the output into *writer*.
|
||||
|
||||
If *obj* is ``NULL``, write the string ``"<NULL>"`` into *writer*.
|
||||
|
||||
On success, return ``0``.
|
||||
On error, set an exception, leave the writer unchanged, and return ``-1``.
|
||||
|
||||
.. versionchanged:: 3.14.4
|
||||
|
||||
Added support for ``NULL``.
|
||||
|
||||
.. c:function:: int PyUnicodeWriter_WriteSubstring(PyUnicodeWriter *writer, PyObject *str, Py_ssize_t start, Py_ssize_t end)
|
||||
|
||||
Write the substring ``str[start:end]`` into *writer*.
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ the same library that the Python runtime is using.
|
|||
objects *globals* and *locals* with the compiler flags specified by
|
||||
*flags*. *globals* must be a dictionary; *locals* can be any object
|
||||
that implements the mapping protocol. The parameter *start* specifies
|
||||
the start symbol and must one of the :ref:`available start symbols <start-symbols>`.
|
||||
the start symbol and must be one of the :ref:`available start symbols <start-symbols>`.
|
||||
|
||||
Returns the result of executing the code as a Python object, or ``NULL`` if an
|
||||
exception was raised.
|
||||
|
|
|
|||
51
Doc/conf.py
51
Doc/conf.py
|
|
@ -33,6 +33,7 @@
|
|||
'issue_role',
|
||||
'lexers',
|
||||
'misc_news',
|
||||
'profiling_trace',
|
||||
'pydoc_topics',
|
||||
'pyspecific',
|
||||
'sphinx.ext.coverage',
|
||||
|
|
@ -42,8 +43,10 @@
|
|||
|
||||
# Skip if downstream redistributors haven't installed them
|
||||
_OPTIONAL_EXTENSIONS = (
|
||||
'linklint.ext',
|
||||
'notfound.extension',
|
||||
'sphinxext.opengraph',
|
||||
'sphinxcontrib.rsvgconverter',
|
||||
)
|
||||
for optional_ext in _OPTIONAL_EXTENSIONS:
|
||||
try:
|
||||
|
|
@ -70,6 +73,7 @@
|
|||
# General substitutions.
|
||||
project = 'Python'
|
||||
copyright = "2001 Python Software Foundation"
|
||||
_doc_authors = 'Python documentation authors'
|
||||
|
||||
# We look for the Include/patchlevel.h file in the current Python source tree
|
||||
# and replace the values accordingly.
|
||||
|
|
@ -174,6 +178,7 @@
|
|||
('c:type', '__int64'),
|
||||
('c:type', 'unsigned __int64'),
|
||||
('c:type', 'double'),
|
||||
('c:type', '_Float16'),
|
||||
# Standard C structures
|
||||
('c:struct', 'in6_addr'),
|
||||
('c:struct', 'in_addr'),
|
||||
|
|
@ -226,10 +231,6 @@
|
|||
# Temporary undocumented names.
|
||||
# In future this list must be empty.
|
||||
nitpick_ignore += [
|
||||
# Do not error nit-picky mode builds when _SubParsersAction.add_parser cannot
|
||||
# be resolved, as the method is currently undocumented. For context, see
|
||||
# https://github.com/python/cpython/pull/103289.
|
||||
('py:meth', '_SubParsersAction.add_parser'),
|
||||
# Attributes/methods/etc. that definitely should be documented better,
|
||||
# but are deferred for now:
|
||||
('py:attr', '__wrapped__'),
|
||||
|
|
@ -361,69 +362,74 @@
|
|||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, document class [howto/manual]).
|
||||
_stdauthor = 'The Python development team'
|
||||
latex_documents = [
|
||||
('c-api/index', 'c-api.tex', 'The Python/C API', _stdauthor, 'manual'),
|
||||
('c-api/index', 'c-api.tex', 'The Python/C API', _doc_authors, 'manual'),
|
||||
(
|
||||
'extending/index',
|
||||
'extending.tex',
|
||||
'Extending and Embedding Python',
|
||||
_stdauthor,
|
||||
_doc_authors,
|
||||
'manual',
|
||||
),
|
||||
(
|
||||
'installing/index',
|
||||
'installing.tex',
|
||||
'Installing Python Modules',
|
||||
_stdauthor,
|
||||
_doc_authors,
|
||||
'manual',
|
||||
),
|
||||
(
|
||||
'library/index',
|
||||
'library.tex',
|
||||
'The Python Library Reference',
|
||||
_stdauthor,
|
||||
_doc_authors,
|
||||
'manual',
|
||||
),
|
||||
(
|
||||
'reference/index',
|
||||
'reference.tex',
|
||||
'The Python Language Reference',
|
||||
_stdauthor,
|
||||
_doc_authors,
|
||||
'manual',
|
||||
),
|
||||
(
|
||||
'tutorial/index',
|
||||
'tutorial.tex',
|
||||
'Python Tutorial',
|
||||
_stdauthor,
|
||||
_doc_authors,
|
||||
'manual',
|
||||
),
|
||||
(
|
||||
'using/index',
|
||||
'using.tex',
|
||||
'Python Setup and Usage',
|
||||
_stdauthor,
|
||||
_doc_authors,
|
||||
'manual',
|
||||
),
|
||||
(
|
||||
'faq/index',
|
||||
'faq.tex',
|
||||
'Python Frequently Asked Questions',
|
||||
_stdauthor,
|
||||
_doc_authors,
|
||||
'manual',
|
||||
),
|
||||
(
|
||||
'whatsnew/' + version,
|
||||
'whatsnew.tex',
|
||||
'What\'s New in Python',
|
||||
'A. M. Kuchling',
|
||||
_doc_authors,
|
||||
'howto',
|
||||
),
|
||||
]
|
||||
# Collect all HOWTOs individually
|
||||
latex_documents.extend(
|
||||
('howto/' + fn[:-4], 'howto-' + fn[:-4] + '.tex', '', _stdauthor, 'howto')
|
||||
(
|
||||
'howto/' + fn[:-4],
|
||||
'howto-' + fn[:-4] + '.tex',
|
||||
'',
|
||||
_doc_authors,
|
||||
'howto',
|
||||
)
|
||||
for fn in os.listdir('howto')
|
||||
if fn.endswith('.rst') and fn != 'index.rst'
|
||||
)
|
||||
|
|
@ -434,7 +440,7 @@
|
|||
# Options for Epub output
|
||||
# -----------------------
|
||||
|
||||
epub_author = 'Python Documentation Authors'
|
||||
epub_author = _doc_authors
|
||||
epub_publisher = 'Python Software Foundation'
|
||||
epub_exclude_files = (
|
||||
'index.xhtml',
|
||||
|
|
@ -558,6 +564,7 @@
|
|||
# mapping unique short aliases to a base URL and a prefix.
|
||||
# https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html
|
||||
extlinks = {
|
||||
"oss-fuzz": ("https://issues.oss-fuzz.com/issues/%s", "#%s"),
|
||||
"pypi": ("https://pypi.org/project/%s/", "%s"),
|
||||
"source": (SOURCE_URI, "%s"),
|
||||
}
|
||||
|
|
@ -569,6 +576,18 @@
|
|||
# Relative filename of the data files
|
||||
refcount_file = 'data/refcounts.dat'
|
||||
stable_abi_file = 'data/stable_abi.dat'
|
||||
threadsafety_file = 'data/threadsafety.dat'
|
||||
|
||||
# Options for notfound.extension
|
||||
# -------------------------------
|
||||
|
||||
if not os.getenv("READTHEDOCS"):
|
||||
if language_code:
|
||||
notfound_urls_prefix = (
|
||||
f'/{language_code.replace("_", "-").lower()}/{version}/'
|
||||
)
|
||||
else:
|
||||
notfound_urls_prefix = f'/{version}/'
|
||||
|
||||
# Options for sphinxext-opengraph
|
||||
# -------------------------------
|
||||
|
|
|
|||
|
|
@ -2427,10 +2427,20 @@ PyType_GetFlags:PyTypeObject*:type:0:
|
|||
PyType_GetName:PyObject*::+1:
|
||||
PyType_GetName:PyTypeObject*:type:0:
|
||||
|
||||
PyType_GetModule:PyObject*::0:
|
||||
PyType_GetModule:PyTypeObject*:type:0:
|
||||
|
||||
PyType_GetModule_DuringGC:PyObject*::0:
|
||||
PyType_GetModule_DuringGC:PyTypeObject*:type:0:
|
||||
|
||||
PyType_GetModuleByToken:PyObject*::+1:
|
||||
PyType_GetModuleByToken:PyTypeObject*:type:0:
|
||||
PyType_GetModuleByToken:PyModuleDef*:def::
|
||||
|
||||
PyType_GetModuleByToken_DuringGC:PyObject*::0:
|
||||
PyType_GetModuleByToken_DuringGC:PyTypeObject*:type:0:
|
||||
PyType_GetModuleByToken_DuringGC:PyModuleDef*:mod_token::
|
||||
|
||||
PyType_GetModuleByDef:PyObject*::0:
|
||||
PyType_GetModuleByDef:PyTypeObject*:type:0:
|
||||
PyType_GetModuleByDef:PyModuleDef*:def::
|
||||
|
|
|
|||
11
Doc/data/stable_abi.dat
generated
11
Doc/data/stable_abi.dat
generated
|
|
@ -470,8 +470,8 @@ func,PyMemoryView_GetContiguous,3.2,,
|
|||
data,PyMemoryView_Type,3.2,,
|
||||
type,PyMethodDef,3.2,,full-abi
|
||||
data,PyMethodDescr_Type,3.2,,
|
||||
type,PyModuleDef,3.2,,full-abi
|
||||
type,PyModuleDef_Base,3.2,,full-abi
|
||||
type,PyModuleDef,3.2,,abi3t-opaque
|
||||
type,PyModuleDef_Base,3.2,,abi3t-opaque
|
||||
func,PyModuleDef_Init,3.5,,
|
||||
type,PyModuleDef_Slot,3.5,,full-abi
|
||||
data,PyModuleDef_Type,3.5,,
|
||||
|
|
@ -495,7 +495,9 @@ func,PyModule_GetName,3.2,,
|
|||
func,PyModule_GetNameObject,3.7,,
|
||||
func,PyModule_GetState,3.2,,
|
||||
func,PyModule_GetStateSize,3.15,,
|
||||
func,PyModule_GetState_DuringGC,3.15,,
|
||||
func,PyModule_GetToken,3.15,,
|
||||
func,PyModule_GetToken_DuringGC,3.15,,
|
||||
func,PyModule_New,3.2,,
|
||||
func,PyModule_NewObject,3.7,,
|
||||
func,PyModule_SetDocString,3.7,,
|
||||
|
|
@ -598,6 +600,7 @@ func,PyObject_GetIter,3.2,,
|
|||
func,PyObject_GetOptionalAttr,3.13,,
|
||||
func,PyObject_GetOptionalAttrString,3.13,,
|
||||
func,PyObject_GetTypeData,3.12,,
|
||||
func,PyObject_GetTypeData_DuringGC,3.15,,
|
||||
func,PyObject_HasAttr,3.2,,
|
||||
func,PyObject_HasAttrString,3.2,,
|
||||
func,PyObject_HasAttrStringWithError,3.13,,
|
||||
|
|
@ -750,13 +753,17 @@ func,PyType_FromSpecWithBases,3.3,,
|
|||
func,PyType_GenericAlloc,3.2,,
|
||||
func,PyType_GenericNew,3.2,,
|
||||
func,PyType_GetBaseByToken,3.14,,
|
||||
func,PyType_GetBaseByToken_DuringGC,3.15,,
|
||||
func,PyType_GetFlags,3.2,,
|
||||
func,PyType_GetFullyQualifiedName,3.13,,
|
||||
func,PyType_GetModule,3.10,,
|
||||
func,PyType_GetModuleByDef,3.13,,
|
||||
func,PyType_GetModuleByToken,3.15,,
|
||||
func,PyType_GetModuleByToken_DuringGC,3.15,,
|
||||
func,PyType_GetModuleName,3.13,,
|
||||
func,PyType_GetModuleState,3.10,,
|
||||
func,PyType_GetModuleState_DuringGC,3.15,,
|
||||
func,PyType_GetModule_DuringGC,3.15,,
|
||||
func,PyType_GetName,3.11,,
|
||||
func,PyType_GetQualName,3.11,,
|
||||
func,PyType_GetSlot,3.4,,
|
||||
|
|
|
|||
284
Doc/data/threadsafety.dat
Normal file
284
Doc/data/threadsafety.dat
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
# Thread safety annotations for C API functions.
|
||||
#
|
||||
# Each line has the form:
|
||||
# function_name : level
|
||||
#
|
||||
# Where level is one of:
|
||||
# incompatible -- not safe even with external locking
|
||||
# compatible -- safe if the caller serializes all access with external locks
|
||||
# distinct -- safe on distinct objects without external synchronization
|
||||
# shared -- safe for concurrent use on the same object
|
||||
# atomic -- atomic
|
||||
#
|
||||
# Lines beginning with '#' are ignored.
|
||||
# The function name must match the C domain identifier used in the documentation.
|
||||
|
||||
# Synchronization primitives (Doc/c-api/synchronization.rst)
|
||||
PyMutex_Lock:atomic:
|
||||
PyMutex_Unlock:atomic:
|
||||
PyMutex_IsLocked:atomic:
|
||||
|
||||
|
||||
# Dictionary objects (Doc/c-api/dict.rst)
|
||||
|
||||
# Type checks - read ob_type pointer, always safe
|
||||
PyDict_Check:atomic:
|
||||
PyDict_CheckExact:atomic:
|
||||
|
||||
# Creation - pure allocation, no shared state
|
||||
PyDict_New:atomic:
|
||||
|
||||
# Lock-free lookups - use _Py_dict_lookup_threadsafe(), no locking.
|
||||
# Atomic with simple types.
|
||||
PyDict_Contains:shared:
|
||||
PyDict_ContainsString:atomic:
|
||||
PyDict_GetItemRef:shared:
|
||||
PyDict_GetItemStringRef:atomic:
|
||||
PyDict_Size:atomic:
|
||||
PyDict_GET_SIZE:atomic:
|
||||
|
||||
# Borrowed-reference lookups - lock-free dict access but returned
|
||||
# borrowed reference is unsafe in free-threaded builds without
|
||||
# external synchronization
|
||||
PyDict_GetItem:compatible:
|
||||
PyDict_GetItemWithError:compatible:
|
||||
PyDict_GetItemString:compatible:
|
||||
PyDict_SetDefault:compatible:
|
||||
|
||||
# Iteration - no locking; returns borrowed refs
|
||||
PyDict_Next:compatible:
|
||||
|
||||
# Single-item mutations - protected by per-object critical section
|
||||
PyDict_SetItem:shared:
|
||||
PyDict_SetItemString:atomic:
|
||||
PyDict_DelItem:shared:
|
||||
PyDict_DelItemString:atomic:
|
||||
PyDict_SetDefaultRef:shared:
|
||||
PyDict_Pop:shared:
|
||||
PyDict_PopString:atomic:
|
||||
|
||||
# Bulk reads - hold per-object lock for duration
|
||||
PyDict_Clear:atomic:
|
||||
PyDict_Copy:atomic:
|
||||
PyDict_Keys:atomic:
|
||||
PyDict_Values:atomic:
|
||||
PyDict_Items:atomic:
|
||||
|
||||
# Merge/update - lock target dict; also lock source when it is a dict
|
||||
PyDict_Update:shared:
|
||||
PyDict_Merge:shared:
|
||||
PyDict_MergeFromSeq2:shared:
|
||||
|
||||
# Watcher registration - no synchronization on interpreter state
|
||||
PyDict_AddWatcher:compatible:
|
||||
PyDict_ClearWatcher:compatible:
|
||||
|
||||
# Per-dict watcher tags - non-atomic RMW on _ma_watcher_tag;
|
||||
# safe on distinct dicts only
|
||||
PyDict_Watch:distinct:
|
||||
PyDict_Unwatch:distinct:
|
||||
|
||||
|
||||
# List objects (Doc/c-api/list.rst)
|
||||
|
||||
# Type checks - read ob_type pointer, always safe
|
||||
PyList_Check:atomic:
|
||||
PyList_CheckExact:atomic:
|
||||
|
||||
# Creation - pure allocation, no shared state
|
||||
PyList_New:atomic:
|
||||
|
||||
# Size - uses atomic load on free-threaded builds
|
||||
PyList_Size:atomic:
|
||||
PyList_GET_SIZE:atomic:
|
||||
|
||||
# Strong-reference lookup - lock-free with atomic ops
|
||||
PyList_GetItemRef:atomic:
|
||||
|
||||
# Borrowed-reference lookups - no locking; returned borrowed
|
||||
# reference is unsafe in free-threaded builds without
|
||||
# external synchronization
|
||||
PyList_GetItem:compatible:
|
||||
PyList_GET_ITEM:compatible:
|
||||
|
||||
# Single-item mutations - hold per-object lock for duration;
|
||||
# appear atomic to lock-free readers
|
||||
PyList_SetItem:atomic:
|
||||
PyList_Append:atomic:
|
||||
|
||||
# Insert - protected by per-object critical section; shifts
|
||||
# elements so lock-free readers may observe intermediate states
|
||||
PyList_Insert:shared:
|
||||
|
||||
# Initialization macro - no synchronization; normally only used
|
||||
# to fill in new lists where there is no previous content
|
||||
PyList_SET_ITEM:compatible:
|
||||
|
||||
# Bulk operations - hold per-object lock for duration
|
||||
PyList_GetSlice:atomic:
|
||||
PyList_AsTuple:atomic:
|
||||
PyList_Clear:atomic:
|
||||
|
||||
# Reverse - protected by per-object critical section; swaps
|
||||
# elements so lock-free readers may observe intermediate states
|
||||
PyList_Reverse:shared:
|
||||
|
||||
# Slice assignment - lock target list; also lock source when it
|
||||
# is a list
|
||||
PyList_SetSlice:shared:
|
||||
|
||||
# Sort - per-object lock held; the list is emptied before sorting
|
||||
# so other threads may observe an empty list, but they won't see the
|
||||
# intermediate states of the sort
|
||||
PyList_Sort:shared:
|
||||
|
||||
# Extend - lock target list; also lock source when it is a
|
||||
# list, set, or dict
|
||||
PyList_Extend:shared:
|
||||
|
||||
# Creation - pure allocation, no shared state
|
||||
PyBytes_FromString:atomic:
|
||||
PyBytes_FromStringAndSize:atomic:
|
||||
PyBytes_DecodeEscape:atomic:
|
||||
|
||||
# Creation from formatting C primitives - pure allocation, no shared state
|
||||
PyBytes_FromFormat:atomic:
|
||||
PyBytes_FromFormatV:atomic:
|
||||
|
||||
# Creation from object - uses buffer protocol so may call arbitrary code;
|
||||
# safe as long as the buffer is not mutated by another thread during the operation
|
||||
PyBytes_FromObject:shared:
|
||||
|
||||
# Size - uses atomic load on free-threaded builds
|
||||
PyBytes_Size:atomic:
|
||||
PyBytes_GET_SIZE:atomic:
|
||||
|
||||
# Raw data - no locking; mutating it is unsafe if the bytes object is shared between threads
|
||||
PyBytes_AsString:compatible:
|
||||
PyBytes_AS_STRING:compatible:
|
||||
PyBytes_AsStringAndSize:compatible:
|
||||
|
||||
# Concatenation - uses buffer protocol; safe as long as buffer is not mutated by another thread during the operation
|
||||
PyBytes_Concat:shared:
|
||||
PyBytes_ConcatAndDel:shared:
|
||||
PyBytes_Join:shared:
|
||||
|
||||
# Resizing - safe if the object is unique
|
||||
_PyBytes_Resize:distinct:
|
||||
|
||||
# Repr - atomic as bytes are immutable
|
||||
PyBytes_Repr:atomic:
|
||||
|
||||
# Creation from object - may call arbitrary code
|
||||
PyByteArray_FromObject:shared:
|
||||
|
||||
# Creation - pure allocation, no shared state
|
||||
PyByteArray_FromStringAndSize:atomic:
|
||||
|
||||
# Concatenation - uses buffer protocol; safe as long as buffer is not mutated by another thread during the operation
|
||||
PyByteArray_Concat:shared:
|
||||
|
||||
# Size - uses atomic load on free-threaded builds
|
||||
PyByteArray_Size:atomic:
|
||||
PyByteArray_GET_SIZE:atomic:
|
||||
|
||||
# Raw data - no locking; mutating it is unsafe if the bytearray object is shared between threads
|
||||
PyByteArray_AsString:compatible:
|
||||
PyByteArray_AS_STRING:compatible:
|
||||
|
||||
# Creation - may iterate the iterable argument, calling arbitrary code.
|
||||
# Atomic for sets, frozensets, dicts, and frozendicts.
|
||||
PySet_New:shared:
|
||||
PyFrozenSet_New:shared:
|
||||
|
||||
# Size - uses atomic load on free-threaded builds
|
||||
PySet_Size:atomic:
|
||||
PySet_GET_SIZE:atomic:
|
||||
|
||||
# Contains - lock-free, atomic with simple types
|
||||
PySet_Contains:shared:
|
||||
|
||||
# Mutations - hold per-object lock for duration
|
||||
# atomic with simple types
|
||||
PySet_Add:shared:
|
||||
PySet_Discard:shared:
|
||||
|
||||
# Pop - hold per-object lock for duration
|
||||
PySet_Pop:atomic:
|
||||
|
||||
# Clear - empties the set before clearing
|
||||
PySet_Clear:atomic:
|
||||
|
||||
# Capsule objects (Doc/c-api/capsule.rst)
|
||||
|
||||
# Type check - read ob_type pointer, always safe
|
||||
PyCapsule_CheckExact:atomic:
|
||||
|
||||
# Creation - pure allocation, no shared state
|
||||
PyCapsule_New:atomic:
|
||||
|
||||
# Validation - reads pointer and name fields; safe on distinct objects
|
||||
PyCapsule_IsValid:distinct:
|
||||
|
||||
# Getters - read struct fields; safe on distinct objects but
|
||||
# concurrent access to the same capsule requires external synchronization
|
||||
PyCapsule_GetPointer:distinct:
|
||||
PyCapsule_GetName:distinct:
|
||||
PyCapsule_GetDestructor:distinct:
|
||||
PyCapsule_GetContext:distinct:
|
||||
|
||||
# Setters - write struct fields; safe on distinct objects but
|
||||
# concurrent access to the same capsule requires external synchronization
|
||||
PyCapsule_SetPointer:distinct:
|
||||
PyCapsule_SetName:distinct:
|
||||
PyCapsule_SetDestructor:distinct:
|
||||
PyCapsule_SetContext:distinct:
|
||||
|
||||
# Import - looks up a capsule from a module attribute and
|
||||
# calls PyCapsule_GetPointer; may call arbitrary code
|
||||
PyCapsule_Import:compatible:
|
||||
|
||||
# Tuple objects
|
||||
|
||||
# Creation - pure allocation, no shared state
|
||||
PyTuple_New:atomic:
|
||||
PyTuple_FromArray:atomic:
|
||||
PyTuple_Pack:atomic:
|
||||
|
||||
# Size - tuples are immutable so size never changes
|
||||
PyTuple_Size:atomic:
|
||||
PyTuple_GET_SIZE:atomic:
|
||||
|
||||
# Borrowed-reference lookups - tuples are immutable so items
|
||||
# never change, however the tuple must be kept alive while using the borrowed reference
|
||||
PyTuple_GetItem:compatible:
|
||||
PyTuple_GET_ITEM:compatible:
|
||||
|
||||
# Slice - creates a new tuple from an existing tuple
|
||||
PyTuple_GetSlice:atomic:
|
||||
|
||||
# SetItem - only usable on tuples with refcount 1
|
||||
PyTuple_SetItem:compatible:
|
||||
PyTuple_SET_ITEM:compatible:
|
||||
|
||||
# Resize - only usable on tuples with refcount 1
|
||||
_PyTuple_Resize:compatible:
|
||||
|
||||
# Struct Sequence objects
|
||||
|
||||
# Creation
|
||||
PyStructSequence_NewType:atomic:
|
||||
PyStructSequence_New:atomic:
|
||||
|
||||
# Initialization - modifies the type object in place
|
||||
PyStructSequence_InitType:distinct:
|
||||
PyStructSequence_InitType2:distinct:
|
||||
|
||||
# Borrowed-reference lookups - same as tuple items
|
||||
PyStructSequence_GetItem:compatible:
|
||||
PyStructSequence_GET_ITEM:compatible:
|
||||
|
||||
# SetItem - only for filling in brand new instances
|
||||
PyStructSequence_SetItem:compatible:
|
||||
PyStructSequence_SET_ITEM:compatible:
|
||||
|
||||
|
|
@ -7,8 +7,6 @@ Pending removal in Python 3.15
|
|||
Use :c:func:`PyWeakref_GetRef` instead. The `pythoncapi-compat project
|
||||
<https://github.com/python/pythoncapi-compat/>`__ can be used to get
|
||||
: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`:
|
||||
|
|
|
|||
4
Doc/deprecations/c-api-pending-removal-in-3.19.rst
Normal file
4
Doc/deprecations/c-api-pending-removal-in-3.19.rst
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Pending removal in Python 3.19
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* :pep:`456` embedders support for the string hashing scheme definition.
|
||||
|
|
@ -15,13 +15,19 @@ Deprecations
|
|||
|
||||
.. include:: pending-removal-in-future.rst
|
||||
|
||||
.. include:: soft-deprecations.rst
|
||||
|
||||
C API deprecations
|
||||
------------------
|
||||
|
||||
.. include:: c-api-pending-removal-in-3.15.rst
|
||||
|
||||
.. include:: c-api-pending-removal-in-3.16.rst
|
||||
|
||||
.. include:: c-api-pending-removal-in-3.18.rst
|
||||
|
||||
.. include:: c-api-pending-removal-in-3.19.rst
|
||||
|
||||
.. include:: c-api-pending-removal-in-3.20.rst
|
||||
|
||||
.. include:: c-api-pending-removal-in-future.rst
|
||||
|
|
|
|||
|
|
@ -54,13 +54,13 @@ Pending removal in Python 3.15
|
|||
|
||||
* :func:`~threading.RLock` will take no arguments in Python 3.15.
|
||||
Passing any arguments has been deprecated since Python 3.14,
|
||||
as the Python version does not permit any arguments,
|
||||
as the Python version does not permit any arguments,
|
||||
but the C version allows any number of positional or keyword arguments,
|
||||
ignoring every argument.
|
||||
|
||||
* :mod:`types`:
|
||||
|
||||
* :class:`types.CodeType`: Accessing :attr:`~codeobject.co_lnotab` was
|
||||
* :class:`types.CodeType`: Accessing :attr:`!codeobject.co_lnotab` was
|
||||
deprecated in :pep:`626`
|
||||
since 3.10 and was planned to be removed in 3.12,
|
||||
but it only got a proper :exc:`DeprecationWarning` in 3.12.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,14 @@
|
|||
Pending removal in Python 3.17
|
||||
------------------------------
|
||||
|
||||
* :mod:`datetime`:
|
||||
|
||||
* :meth:`~datetime.datetime.strptime` calls using a format string containing
|
||||
``%e`` (day of month) without a year.
|
||||
This has been deprecated since Python 3.15.
|
||||
(Contributed by Stan Ulbrych in :gh:`70647`.)
|
||||
|
||||
|
||||
* :mod:`collections.abc`:
|
||||
|
||||
- :class:`collections.abc.ByteString` is scheduled for removal in Python 3.17.
|
||||
|
|
@ -27,7 +35,7 @@ Pending removal in Python 3.17
|
|||
|
||||
- Passing non-ascii *encoding* names to :func:`encodings.normalize_encoding`
|
||||
is deprecated and scheduled for removal in Python 3.17.
|
||||
(Contributed by Stan Ulbrych in :gh:`136702`)
|
||||
(Contributed by Stan Ulbrych in :gh:`136702`.)
|
||||
|
||||
* :mod:`typing`:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
Pending removal in Python 3.18
|
||||
------------------------------
|
||||
|
||||
* No longer accept a boolean value when a file descriptor is expected.
|
||||
(Contributed by Serhiy Storchaka in :gh:`82626`.)
|
||||
|
||||
* :mod:`decimal`:
|
||||
|
||||
* The non-standard and undocumented :class:`~decimal.Decimal` format
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
Pending removal in Python 3.20
|
||||
------------------------------
|
||||
|
||||
* Calling the ``__new__()`` method of :class:`struct.Struct` without the
|
||||
*format* argument is deprecated and will be removed in Python 3.20. Calling
|
||||
:meth:`~object.__init__` method on initialized :class:`~struct.Struct`
|
||||
objects is deprecated and will be removed in Python 3.20.
|
||||
|
||||
(Contributed by Sergey B Kirpichev and Serhiy Storchaka in :gh:`143715`.)
|
||||
|
||||
* The ``__version__``, ``version`` and ``VERSION`` attributes have been
|
||||
deprecated in these standard library modules and will be removed in
|
||||
Python 3.20. Use :py:data:`sys.version_info` instead.
|
||||
|
|
@ -21,6 +28,7 @@ Pending removal in Python 3.20
|
|||
- :mod:`re`
|
||||
- :mod:`socketserver`
|
||||
- :mod:`tabnanny`
|
||||
- :mod:`tarfile`
|
||||
- :mod:`tkinter.font`
|
||||
- :mod:`tkinter.ttk`
|
||||
- :mod:`wsgiref.simple_server`
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ although there is currently no date scheduled for their removal.
|
|||
* Support for ``__complex__()`` method returning a strict subclass of
|
||||
:class:`complex`: these methods will be required to return an instance of
|
||||
:class:`complex`.
|
||||
* Delegation of ``int()`` to ``__trunc__()`` method.
|
||||
* Passing a complex number as the *real* or *imag* argument in the
|
||||
:func:`complex` constructor is now deprecated; it should only be passed
|
||||
as a single positional argument.
|
||||
|
|
@ -48,7 +47,7 @@ although there is currently no date scheduled for their removal.
|
|||
|
||||
* :mod:`codecs`: use :func:`open` instead of :func:`codecs.open`. (:gh:`133038`)
|
||||
|
||||
* :attr:`codeobject.co_lnotab`: use the :meth:`codeobject.co_lines` method
|
||||
* :attr:`!codeobject.co_lnotab`: use the :meth:`codeobject.co_lines` method
|
||||
instead.
|
||||
|
||||
* :mod:`datetime`:
|
||||
|
|
@ -78,6 +77,14 @@ although there is currently no date scheduled for their removal.
|
|||
|
||||
* :mod:`os`: Calling :func:`os.register_at_fork` in a multi-threaded process.
|
||||
|
||||
* :mod:`os.path`: :func:`os.path.commonprefix` is deprecated, use
|
||||
:func:`os.path.commonpath` for path prefixes. The :func:`os.path.commonprefix`
|
||||
function is being deprecated due to having a misleading name and module.
|
||||
The function is not safe to use for path prefixes despite being included in a
|
||||
module about path manipulation, meaning it is easy to accidentally
|
||||
introduce path traversal vulnerabilities into Python programs by using this
|
||||
function.
|
||||
|
||||
* :class:`!pydoc.ErrorDuringImport`: A tuple value for *exc_info* parameter is
|
||||
deprecated, use an exception instance.
|
||||
|
||||
|
|
|
|||
21
Doc/deprecations/soft-deprecations.rst
Normal file
21
Doc/deprecations/soft-deprecations.rst
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
Soft deprecations
|
||||
-----------------
|
||||
|
||||
There are no plans to remove :term:`soft deprecated` APIs.
|
||||
|
||||
* :func:`re.match` and :meth:`re.Pattern.match` are now
|
||||
:term:`soft deprecated` in favor of the new :func:`re.prefixmatch` and
|
||||
:meth:`re.Pattern.prefixmatch` APIs, which have been added as alternate,
|
||||
more explicit names. These are intended to be used to alleviate confusion
|
||||
around what *match* means by following the Zen of Python's *"Explicit is
|
||||
better than implicit"* mantra. Most other language regular expression
|
||||
libraries use an API named *match* to mean what Python has always called
|
||||
*search*.
|
||||
|
||||
We **do not** plan to remove the older :func:`!match` name, as it has been
|
||||
used in code for over 30 years. Code supporting older versions of Python
|
||||
should continue to use :func:`!match`, while new code should prefer
|
||||
:func:`!prefixmatch`. See :ref:`prefixmatch-vs-match`.
|
||||
|
||||
(Contributed by Gregory P. Smith in :gh:`86519` and
|
||||
Hugo van Kemenade in :gh:`148100`.)
|
||||
|
|
@ -903,9 +903,6 @@ define this symbol).
|
|||
Providing a C API for an Extension Module
|
||||
=========================================
|
||||
|
||||
.. sectionauthor:: Konrad Hinsen <hinsen@cnrs-orleans.fr>
|
||||
|
||||
|
||||
Many extension modules just provide new functions and types to be used from
|
||||
Python, but sometimes the code in an extension module can be useful for other
|
||||
extension modules. For example, an extension module could implement a type
|
||||
|
|
|
|||
|
|
@ -265,12 +265,19 @@ Define this array just before your export hook:
|
|||
|
||||
.. code-block:: c
|
||||
|
||||
PyABIInfo_VAR(abi_info);
|
||||
|
||||
static PyModuleDef_Slot spam_slots[] = {
|
||||
{Py_mod_abi, &abi_info},
|
||||
{Py_mod_name, "spam"},
|
||||
{Py_mod_doc, "A wonderful module with an example function"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
The ``PyABIInfo_VAR(abi_info);`` macro and the :c:data:`Py_mod_abi` slot
|
||||
are a bit of boilerplate that helps prevent extensions compiled for
|
||||
a different version of Python from crashing the interpreter.
|
||||
|
||||
For both :c:data:`Py_mod_name` and :c:data:`Py_mod_doc`, the values are C
|
||||
strings -- that is, NUL-terminated, UTF-8 encoded byte arrays.
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,6 @@
|
|||
Defining Extension Types: Tutorial
|
||||
**********************************
|
||||
|
||||
.. sectionauthor:: Michael Hudson <mwh@python.net>
|
||||
.. sectionauthor:: Dave Kuhlman <dkuhlman@rexx.com>
|
||||
.. sectionauthor:: Jim Fulton <jim@zope.com>
|
||||
|
||||
|
||||
Python allows the writer of a C extension module to define new types that
|
||||
can be manipulated from Python code, much like the built-in :class:`str`
|
||||
and :class:`list` types. The code for all extension types follows a
|
||||
|
|
|
|||
|
|
@ -47,9 +47,6 @@ things manually, it may be instructive to study the project file for the
|
|||
Differences Between Unix and Windows
|
||||
====================================
|
||||
|
||||
.. sectionauthor:: Chris Phoenix <cphoenix@best.com>
|
||||
|
||||
|
||||
Unix and Windows use completely different paradigms for run-time loading of
|
||||
code. Before you try to build a module that can be dynamically loaded, be aware
|
||||
of how your system works.
|
||||
|
|
@ -109,9 +106,6 @@ separate copy.
|
|||
Using DLLs in Practice
|
||||
======================
|
||||
|
||||
.. sectionauthor:: Chris Phoenix <cphoenix@best.com>
|
||||
|
||||
|
||||
Windows Python is built in Microsoft Visual C++; using other compilers may or
|
||||
may not work. The rest of this section is MSVC++ specific.
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ Programming FAQ
|
|||
|
||||
.. contents::
|
||||
|
||||
General Questions
|
||||
General questions
|
||||
=================
|
||||
|
||||
Is there a source code level debugger with breakpoints, single-stepping, etc.?
|
||||
------------------------------------------------------------------------------
|
||||
Is there a source code-level debugger with breakpoints and single-stepping?
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Yes.
|
||||
|
||||
|
|
@ -25,8 +25,7 @@ Reference Manual <pdb>`. You can also write your own debugger by using the code
|
|||
for pdb as an example.
|
||||
|
||||
The IDLE interactive development environment, which is part of the standard
|
||||
Python distribution (normally available as
|
||||
`Tools/scripts/idle3 <https://github.com/python/cpython/blob/main/Tools/scripts/idle3>`_),
|
||||
Python distribution (normally available as :mod:`idlelib`),
|
||||
includes a graphical debugger.
|
||||
|
||||
PythonWin is a Python IDE that includes a GUI debugger based on pdb. The
|
||||
|
|
@ -48,7 +47,6 @@ There are a number of commercial Python IDEs that include graphical debuggers.
|
|||
They include:
|
||||
|
||||
* `Wing IDE <https://wingware.com/>`_
|
||||
* `Komodo IDE <https://www.activestate.com/products/komodo-ide/>`_
|
||||
* `PyCharm <https://www.jetbrains.com/pycharm/>`_
|
||||
|
||||
|
||||
|
|
@ -57,13 +55,15 @@ Are there tools to help find bugs or perform static analysis?
|
|||
|
||||
Yes.
|
||||
|
||||
`Pylint <https://pylint.pycqa.org/en/latest/index.html>`_ and
|
||||
`Pyflakes <https://github.com/PyCQA/pyflakes>`_ do basic checking that will
|
||||
`Ruff <https://docs.astral.sh/ruff/>`__,
|
||||
`Pylint <https://pylint.readthedocs.io/>`__ and
|
||||
`Pyflakes <https://github.com/PyCQA/pyflakes>`__ do basic checking that will
|
||||
help you catch bugs sooner.
|
||||
|
||||
Static type checkers such as `Mypy <https://mypy-lang.org/>`_,
|
||||
`Pyre <https://pyre-check.org/>`_, and
|
||||
`Pytype <https://github.com/google/pytype>`_ can check type hints in Python
|
||||
Static type checkers such as `mypy <https://mypy-lang.org/>`__,
|
||||
`ty <https://docs.astral.sh/ty/>`__,
|
||||
`Pyrefly <https://pyrefly.org/>`__, and
|
||||
`pytype <https://github.com/google/pytype>`__ can check type hints in Python
|
||||
source code.
|
||||
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ set of modules required by a program and bind these modules together with a
|
|||
Python binary to produce a single executable.
|
||||
|
||||
One is to use the freeze tool, which is included in the Python source tree as
|
||||
`Tools/freeze <https://github.com/python/cpython/tree/main/Tools/freeze>`_.
|
||||
:source:`Tools/freeze`.
|
||||
It converts Python byte code to C arrays; with a C compiler you can
|
||||
embed all your modules into a new program, which is then linked with the
|
||||
standard Python modules.
|
||||
|
|
@ -103,6 +103,7 @@ executables:
|
|||
* `py2app <https://github.com/ronaldoussoren/py2app>`_ (macOS only)
|
||||
* `py2exe <https://www.py2exe.org/>`_ (Windows only)
|
||||
|
||||
|
||||
Are there coding standards or a style guide for Python programs?
|
||||
----------------------------------------------------------------
|
||||
|
||||
|
|
@ -110,7 +111,7 @@ Yes. The coding style required for standard library modules is documented as
|
|||
:pep:`8`.
|
||||
|
||||
|
||||
Core Language
|
||||
Core language
|
||||
=============
|
||||
|
||||
.. _faq-unboundlocalerror:
|
||||
|
|
@ -143,7 +144,7 @@ results in an :exc:`!UnboundLocalError`:
|
|||
>>> foo()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
UnboundLocalError: local variable 'x' referenced before assignment
|
||||
UnboundLocalError: cannot access local variable 'x' where it is not associated with a value
|
||||
|
||||
This is because when you make an assignment to a variable in a scope, that
|
||||
variable becomes local to that scope and shadows any similarly named variable
|
||||
|
|
@ -208,7 +209,7 @@ Why do lambdas defined in a loop with different values all return the same resul
|
|||
----------------------------------------------------------------------------------
|
||||
|
||||
Assume you use a for loop to define a few different lambdas (or even plain
|
||||
functions), e.g.::
|
||||
functions), for example::
|
||||
|
||||
>>> squares = []
|
||||
>>> for x in range(5):
|
||||
|
|
@ -227,7 +228,7 @@ they all return ``16``::
|
|||
This happens because ``x`` is not local to the lambdas, but is defined in
|
||||
the outer scope, and it is accessed when the lambda is called --- not when it
|
||||
is defined. At the end of the loop, the value of ``x`` is ``4``, so all the
|
||||
functions now return ``4**2``, i.e. ``16``. You can also verify this by
|
||||
functions now return ``4**2``, that is ``16``. You can also verify this by
|
||||
changing the value of ``x`` and see how the results of the lambdas change::
|
||||
|
||||
>>> x = 8
|
||||
|
|
@ -298,9 +299,9 @@ using multiple imports per line uses less screen space.
|
|||
|
||||
It's good practice if you import modules in the following order:
|
||||
|
||||
1. standard library modules -- e.g. :mod:`sys`, :mod:`os`, :mod:`argparse`, :mod:`re`
|
||||
1. standard library modules -- such as :mod:`sys`, :mod:`os`, :mod:`argparse`, :mod:`re`
|
||||
2. third-party library modules (anything installed in Python's site-packages
|
||||
directory) -- e.g. :mod:`!dateutil`, :mod:`!requests`, :mod:`!PIL.Image`
|
||||
directory) -- such as :pypi:`dateutil`, :pypi:`requests`, :pypi:`tzdata`
|
||||
3. locally developed modules
|
||||
|
||||
It is sometimes necessary to move imports to a function or class to avoid
|
||||
|
|
@ -494,11 +495,11 @@ new objects).
|
|||
|
||||
In other words:
|
||||
|
||||
* If we have a mutable object (:class:`list`, :class:`dict`, :class:`set`,
|
||||
etc.), we can use some specific operations to mutate it and all the variables
|
||||
* If we have a mutable object (such as :class:`list`, :class:`dict`, :class:`set`),
|
||||
we can use some specific operations to mutate it and all the variables
|
||||
that refer to it will see the change.
|
||||
* If we have an immutable object (:class:`str`, :class:`int`, :class:`tuple`,
|
||||
etc.), all the variables that refer to it will always see the same value,
|
||||
* If we have an immutable object (such as :class:`str`, :class:`int`, :class:`tuple`),
|
||||
all the variables that refer to it will always see the same value,
|
||||
but operations that transform that value into a new value always return a new
|
||||
object.
|
||||
|
||||
|
|
@ -511,7 +512,7 @@ How do I write a function with output parameters (call by reference)?
|
|||
|
||||
Remember that arguments are passed by assignment in Python. Since assignment
|
||||
just creates references to objects, there's no alias between an argument name in
|
||||
the caller and callee, and so no call-by-reference per se. You can achieve the
|
||||
the caller and callee, and consequently no call-by-reference. You can achieve the
|
||||
desired effect in a number of ways.
|
||||
|
||||
1) By returning a tuple of the results::
|
||||
|
|
@ -714,8 +715,8 @@ not::
|
|||
|
||||
"a" in ("b", "a")
|
||||
|
||||
The same is true of the various assignment operators (``=``, ``+=`` etc). They
|
||||
are not truly operators but syntactic delimiters in assignment statements.
|
||||
The same is true of the various assignment operators (``=``, ``+=``, and so on).
|
||||
They are not truly operators but syntactic delimiters in assignment statements.
|
||||
|
||||
|
||||
Is there an equivalent of C's "?:" ternary operator?
|
||||
|
|
@ -868,9 +869,9 @@ with either a space or parentheses.
|
|||
How do I convert a string to a number?
|
||||
--------------------------------------
|
||||
|
||||
For integers, use the built-in :func:`int` type constructor, e.g. ``int('144')
|
||||
For integers, use the built-in :func:`int` type constructor, for example, ``int('144')
|
||||
== 144``. Similarly, :func:`float` converts to a floating-point number,
|
||||
e.g. ``float('144') == 144.0``.
|
||||
for example, ``float('144') == 144.0``.
|
||||
|
||||
By default, these interpret the number as decimal, so that ``int('0144') ==
|
||||
144`` holds true, and ``int('0x144')`` raises :exc:`ValueError`. ``int(string,
|
||||
|
|
@ -887,18 +888,18 @@ unwanted side effects. For example, someone could pass
|
|||
directory.
|
||||
|
||||
:func:`eval` also has the effect of interpreting numbers as Python expressions,
|
||||
so that e.g. ``eval('09')`` gives a syntax error because Python does not allow
|
||||
so that, for example, ``eval('09')`` gives a syntax error because Python does not allow
|
||||
leading '0' in a decimal number (except '0').
|
||||
|
||||
|
||||
How do I convert a number to a string?
|
||||
--------------------------------------
|
||||
|
||||
To convert, e.g., the number ``144`` to the string ``'144'``, use the built-in type
|
||||
For example, to convert the number ``144`` to the string ``'144'``, use the built-in type
|
||||
constructor :func:`str`. If you want a hexadecimal or octal representation, use
|
||||
the built-in functions :func:`hex` or :func:`oct`. For fancy formatting, see
|
||||
the :ref:`f-strings` and :ref:`formatstrings` sections,
|
||||
e.g. ``"{:04d}".format(144)`` yields
|
||||
the :ref:`f-strings` and :ref:`formatstrings` sections.
|
||||
For example, ``"{:04d}".format(144)`` yields
|
||||
``'0144'`` and ``"{:.3f}".format(1.0/3.0)`` yields ``'0.333'``.
|
||||
|
||||
|
||||
|
|
@ -908,7 +909,7 @@ How do I modify a string in place?
|
|||
You can't, because strings are immutable. In most situations, you should
|
||||
simply construct a new string from the various parts you want to assemble
|
||||
it from. However, if you need an object with the ability to modify in-place
|
||||
unicode data, try using an :class:`io.StringIO` object or the :mod:`array`
|
||||
Unicode data, try using an :class:`io.StringIO` object or the :mod:`array`
|
||||
module::
|
||||
|
||||
>>> import io
|
||||
|
|
@ -1066,13 +1067,14 @@ the raw string::
|
|||
|
||||
Also see the specification in the :ref:`language reference <strings>`.
|
||||
|
||||
|
||||
Performance
|
||||
===========
|
||||
|
||||
My program is too slow. How do I speed it up?
|
||||
---------------------------------------------
|
||||
|
||||
That's a tough one, in general. First, here are a list of things to
|
||||
That's a tough one, in general. First, here is a list of things to
|
||||
remember before diving further:
|
||||
|
||||
* Performance characteristics vary across Python implementations. This FAQ
|
||||
|
|
@ -1125,6 +1127,7 @@ yourself.
|
|||
The wiki page devoted to `performance tips
|
||||
<https://wiki.python.org/moin/PythonSpeed/PerformanceTips>`_.
|
||||
|
||||
|
||||
.. _efficient_string_concatenation:
|
||||
|
||||
What is the most efficient way to concatenate many strings together?
|
||||
|
|
@ -1143,7 +1146,7 @@ them into a list and call :meth:`str.join` at the end::
|
|||
chunks.append(s)
|
||||
result = ''.join(chunks)
|
||||
|
||||
(another reasonably efficient idiom is to use :class:`io.StringIO`)
|
||||
(Another reasonably efficient idiom is to use :class:`io.StringIO`.)
|
||||
|
||||
To accumulate many :class:`bytes` objects, the recommended idiom is to extend
|
||||
a :class:`bytearray` object using in-place concatenation (the ``+=`` operator)::
|
||||
|
|
@ -1153,7 +1156,7 @@ a :class:`bytearray` object using in-place concatenation (the ``+=`` operator)::
|
|||
result += b
|
||||
|
||||
|
||||
Sequences (Tuples/Lists)
|
||||
Sequences (tuples/lists)
|
||||
========================
|
||||
|
||||
How do I convert between tuples and lists?
|
||||
|
|
@ -1217,8 +1220,8 @@ list, deleting duplicates as you go::
|
|||
else:
|
||||
last = mylist[i]
|
||||
|
||||
If all elements of the list may be used as set keys (i.e. they are all
|
||||
:term:`hashable`) this is often faster ::
|
||||
If all elements of the list may be used as set keys (that is, they are all
|
||||
:term:`hashable`) this is often faster::
|
||||
|
||||
mylist = list(set(mylist))
|
||||
|
||||
|
|
@ -1254,7 +1257,7 @@ difference is that a Python list can contain objects of many different types.
|
|||
The ``array`` module also provides methods for creating arrays of fixed types
|
||||
with compact representations, but they are slower to index than lists. Also
|
||||
note that `NumPy <https://numpy.org/>`_
|
||||
and other third party packages define array-like structures with
|
||||
and other third-party packages define array-like structures with
|
||||
various characteristics as well.
|
||||
|
||||
To get Lisp-style linked lists, you can emulate *cons cells* using tuples::
|
||||
|
|
@ -1324,7 +1327,7 @@ Or, you can use an extension that provides a matrix datatype; `NumPy
|
|||
How do I apply a method or function to a sequence of objects?
|
||||
-------------------------------------------------------------
|
||||
|
||||
To call a method or function and accumulate the return values is a list,
|
||||
To call a method or function and accumulate the return values in a list,
|
||||
a :term:`list comprehension` is an elegant solution::
|
||||
|
||||
result = [obj.method() for obj in mylist]
|
||||
|
|
@ -1340,6 +1343,7 @@ a plain :keyword:`for` loop will suffice::
|
|||
for obj in mylist:
|
||||
function(obj)
|
||||
|
||||
|
||||
.. _faq-augmented-assignment-tuple-error:
|
||||
|
||||
Why does a_tuple[i] += ['item'] raise an exception when the addition works?
|
||||
|
|
@ -1444,7 +1448,7 @@ How can I sort one list by values from another list?
|
|||
----------------------------------------------------
|
||||
|
||||
Merge them into an iterator of tuples, sort the resulting list, and then pick
|
||||
out the element you want. ::
|
||||
out the element you want.
|
||||
|
||||
>>> list1 = ["what", "I'm", "sorting", "by"]
|
||||
>>> list2 = ["something", "else", "to", "sort"]
|
||||
|
|
@ -1504,14 +1508,15 @@ How do I check if an object is an instance of a given class or of a subclass of
|
|||
Use the built-in function :func:`isinstance(obj, cls) <isinstance>`. You can
|
||||
check if an object
|
||||
is an instance of any of a number of classes by providing a tuple instead of a
|
||||
single class, e.g. ``isinstance(obj, (class1, class2, ...))``, and can also
|
||||
check whether an object is one of Python's built-in types, e.g.
|
||||
single class, for example, ``isinstance(obj, (class1, class2, ...))``, and can also
|
||||
check whether an object is one of Python's built-in types, for example,
|
||||
``isinstance(obj, str)`` or ``isinstance(obj, (int, float, complex))``.
|
||||
|
||||
Note that :func:`isinstance` also checks for virtual inheritance from an
|
||||
:term:`abstract base class`. So, the test will return ``True`` for a
|
||||
registered class even if hasn't directly or indirectly inherited from it. To
|
||||
test for "true inheritance", scan the :term:`MRO` of the class:
|
||||
test for "true inheritance", scan the :term:`method resolution order` (MRO) of
|
||||
the class:
|
||||
|
||||
.. testcode::
|
||||
|
||||
|
|
@ -1574,7 +1579,7 @@ call it::
|
|||
What is delegation?
|
||||
-------------------
|
||||
|
||||
Delegation is an object oriented technique (also called a design pattern).
|
||||
Delegation is an object-oriented technique (also called a design pattern).
|
||||
Let's say you have an object ``x`` and want to change the behaviour of just one
|
||||
of its methods. You can create a new class that provides a new implementation
|
||||
of the method you're interested in changing and delegates all other methods to
|
||||
|
|
@ -1645,7 +1650,7 @@ How can I organize my code to make it easier to change the base class?
|
|||
|
||||
You could assign the base class to an alias and derive from the alias. Then all
|
||||
you have to change is the value assigned to the alias. Incidentally, this trick
|
||||
is also handy if you want to decide dynamically (e.g. depending on availability
|
||||
is also handy if you want to decide dynamically (such as depending on availability
|
||||
of resources) which base class to use. Example::
|
||||
|
||||
class Base:
|
||||
|
|
@ -1710,9 +1715,9 @@ How can I overload constructors (or methods) in Python?
|
|||
This answer actually applies to all methods, but the question usually comes up
|
||||
first in the context of constructors.
|
||||
|
||||
In C++ you'd write
|
||||
In C++ you'd write:
|
||||
|
||||
.. code-block:: c
|
||||
.. code-block:: c++
|
||||
|
||||
class C {
|
||||
C() { cout << "No arguments\n"; }
|
||||
|
|
@ -1731,7 +1736,7 @@ default arguments. For example::
|
|||
|
||||
This is not entirely equivalent, but close enough in practice.
|
||||
|
||||
You could also try a variable-length argument list, e.g. ::
|
||||
You could also try a variable-length argument list, for example::
|
||||
|
||||
def __init__(self, *args):
|
||||
...
|
||||
|
|
@ -1774,6 +1779,7 @@ to use private variable names at all.
|
|||
The :ref:`private name mangling specifications <private-name-mangling>`
|
||||
for details and special cases.
|
||||
|
||||
|
||||
My class defines __del__ but it is not called when I delete the object.
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
|
|
@ -1783,7 +1789,7 @@ The :keyword:`del` statement does not necessarily call :meth:`~object.__del__` -
|
|||
decrements the object's reference count, and if this reaches zero
|
||||
:meth:`!__del__` is called.
|
||||
|
||||
If your data structures contain circular links (e.g. a tree where each child has
|
||||
If your data structures contain circular links (for example, a tree where each child has
|
||||
a parent reference and each parent has a list of children) the reference counts
|
||||
will never go back to zero. Once in a while Python runs an algorithm to detect
|
||||
such cycles, but the garbage collector might run some time after the last
|
||||
|
|
@ -1852,6 +1858,8 @@ to the object:
|
|||
13891296
|
||||
|
||||
|
||||
.. _faq-identity-with-is:
|
||||
|
||||
When can I rely on identity tests with the *is* operator?
|
||||
---------------------------------------------------------
|
||||
|
||||
|
|
@ -1883,9 +1891,9 @@ are preferred. In particular, identity tests should not be used to check
|
|||
constants such as :class:`int` and :class:`str` which aren't guaranteed to be
|
||||
singletons::
|
||||
|
||||
>>> a = 1000
|
||||
>>> b = 500
|
||||
>>> c = b + 500
|
||||
>>> a = 10_000_000
|
||||
>>> b = 5_000_000
|
||||
>>> c = b + 5_000_000
|
||||
>>> a is c
|
||||
False
|
||||
|
||||
|
|
@ -1954,9 +1962,9 @@ parent class:
|
|||
|
||||
.. testcode::
|
||||
|
||||
from datetime import date
|
||||
import datetime as dt
|
||||
|
||||
class FirstOfMonthDate(date):
|
||||
class FirstOfMonthDate(dt.date):
|
||||
"Always choose the first day of the month"
|
||||
def __new__(cls, year, month, day):
|
||||
return super().__new__(cls, year, month, 1)
|
||||
|
|
@ -1999,7 +2007,7 @@ The two principal tools for caching methods are
|
|||
former stores results at the instance level and the latter at the class
|
||||
level.
|
||||
|
||||
The *cached_property* approach only works with methods that do not take
|
||||
The ``cached_property`` approach only works with methods that do not take
|
||||
any arguments. It does not create a reference to the instance. The
|
||||
cached method result will be kept only as long as the instance is alive.
|
||||
|
||||
|
|
@ -2008,7 +2016,7 @@ method result will be released right away. The disadvantage is that if
|
|||
instances accumulate, so too will the accumulated method results. They
|
||||
can grow without bound.
|
||||
|
||||
The *lru_cache* approach works with methods that have :term:`hashable`
|
||||
The ``lru_cache`` approach works with methods that have :term:`hashable`
|
||||
arguments. It creates a reference to the instance unless special
|
||||
efforts are made to pass in weak references.
|
||||
|
||||
|
|
@ -2042,11 +2050,11 @@ This example shows the various techniques::
|
|||
# Depends on the station_id, date, and units.
|
||||
|
||||
The above example assumes that the *station_id* never changes. If the
|
||||
relevant instance attributes are mutable, the *cached_property* approach
|
||||
relevant instance attributes are mutable, the ``cached_property`` approach
|
||||
can't be made to work because it cannot detect changes to the
|
||||
attributes.
|
||||
|
||||
To make the *lru_cache* approach work when the *station_id* is mutable,
|
||||
To make the ``lru_cache`` approach work when the *station_id* is mutable,
|
||||
the class needs to define the :meth:`~object.__eq__` and :meth:`~object.__hash__`
|
||||
methods so that the cache can detect relevant attribute updates::
|
||||
|
||||
|
|
@ -2092,10 +2100,10 @@ one user but run as another, such as if you are testing with a web server.
|
|||
|
||||
Unless the :envvar:`PYTHONDONTWRITEBYTECODE` environment variable is set,
|
||||
creation of a .pyc file is automatic if you're importing a module and Python
|
||||
has the ability (permissions, free space, etc...) to create a ``__pycache__``
|
||||
has the ability (permissions, free space, and so on) to create a ``__pycache__``
|
||||
subdirectory and write the compiled module to that subdirectory.
|
||||
|
||||
Running Python on a top level script is not considered an import and no
|
||||
Running Python on a top-level script is not considered an import and no
|
||||
``.pyc`` will be created. For example, if you have a top-level module
|
||||
``foo.py`` that imports another module ``xyz.py``, when you run ``foo`` (by
|
||||
typing ``python foo.py`` as a shell command), a ``.pyc`` will be created for
|
||||
|
|
@ -2114,7 +2122,7 @@ the ``compile()`` function in that module interactively::
|
|||
|
||||
This will write the ``.pyc`` to a ``__pycache__`` subdirectory in the same
|
||||
location as ``foo.py`` (or you can override that with the optional parameter
|
||||
``cfile``).
|
||||
*cfile*).
|
||||
|
||||
You can also automatically compile all files in a directory or directories using
|
||||
the :mod:`compileall` module. You can do it from the shell prompt by running
|
||||
|
|
@ -2219,7 +2227,7 @@ changed module, do this::
|
|||
importlib.reload(modname)
|
||||
|
||||
Warning: this technique is not 100% fool-proof. In particular, modules
|
||||
containing statements like ::
|
||||
containing statements like::
|
||||
|
||||
from modname import some_objects
|
||||
|
||||
|
|
|
|||
|
|
@ -951,6 +951,16 @@ Glossary
|
|||
to locks exist such as queues, producer/consumer patterns, and
|
||||
thread-local state. See also :term:`deadlock`, and :term:`reentrant`.
|
||||
|
||||
lock-free
|
||||
An operation that does not acquire any :term:`lock` and uses atomic CPU
|
||||
instructions to ensure correctness. Lock-free operations can execute
|
||||
concurrently without blocking each other and cannot be blocked by
|
||||
operations that hold locks. In :term:`free-threaded <free threading>`
|
||||
Python, built-in types like :class:`dict` and :class:`list` provide
|
||||
lock-free read operations, which means other threads may observe
|
||||
intermediate states during multi-step modifications even when those
|
||||
modifications hold the :term:`per-object lock`.
|
||||
|
||||
loader
|
||||
An object that loads a module.
|
||||
It must define the :meth:`!exec_module` and :meth:`!create_module` methods
|
||||
|
|
@ -1217,6 +1227,16 @@ Glossary
|
|||
<faq-argument-vs-parameter>`, the :class:`inspect.Parameter` class, the
|
||||
:ref:`function` section, and :pep:`362`.
|
||||
|
||||
per-object lock
|
||||
A :term:`lock` associated with an individual object instance rather than
|
||||
a global lock shared across all objects. In :term:`free-threaded
|
||||
<free threading>` Python, built-in types like :class:`dict` and
|
||||
:class:`list` use per-object locks to allow concurrent operations on
|
||||
different objects while serializing operations on the same object.
|
||||
Operations that hold the per-object lock prevent other locking operations
|
||||
on the same object from proceeding, but do not block :term:`lock-free`
|
||||
operations.
|
||||
|
||||
path entry
|
||||
A single location on the :term:`import path` which the :term:`path
|
||||
based finder` consults to find modules for importing.
|
||||
|
|
@ -1339,7 +1359,7 @@ Glossary
|
|||
'email.mime.text'
|
||||
|
||||
race condition
|
||||
A condition of a program where the its behavior
|
||||
A condition of a program where the behavior
|
||||
depends on the relative timing or ordering of events, particularly in
|
||||
multi-threaded programs. Race conditions can lead to
|
||||
:term:`non-deterministic` behavior and bugs that are difficult to
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue