mirror of
https://github.com/python/cpython.git
synced 2025-12-23 09:19:18 +00:00
Compare commits
No commits in common. "main" and "v3.15.0a1" have entirely different histories.
1157 changed files with 31230 additions and 130486 deletions
|
|
@ -1,73 +0,0 @@
|
|||
{
|
||||
"image": "ghcr.io/python/wasicontainer:latest",
|
||||
"onCreateCommand": [
|
||||
// Install common tooling.
|
||||
"dnf",
|
||||
"install",
|
||||
"-y",
|
||||
// For umask fix below.
|
||||
"/usr/bin/setfacl"
|
||||
],
|
||||
"updateContentCommand": {
|
||||
// Using the shell for `nproc` usage.
|
||||
"python": "python3 Tools/wasm/wasi build --quiet -- --with-pydebug -C"
|
||||
},
|
||||
"postCreateCommand": {
|
||||
// https://github.com/orgs/community/discussions/26026
|
||||
"umask fix: workspace": ["sudo", "setfacl", "-bnR", "."],
|
||||
"umask fix: /tmp": ["sudo", "setfacl", "-bnR", "/tmp"]
|
||||
},
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
// Highlighting for Parser/Python.asdl.
|
||||
"brettcannon.zephyr-asdl",
|
||||
// Highlighting for configure.ac.
|
||||
"maelvalais.autoconf",
|
||||
// C auto-complete.
|
||||
"ms-vscode.cpptools",
|
||||
// Python auto-complete.
|
||||
"ms-python.python"
|
||||
],
|
||||
"settings": {
|
||||
"C_Cpp.default.compilerPath": "/usr/bin/clang",
|
||||
"C_Cpp.default.cStandard": "c11",
|
||||
"C_Cpp.default.defines": [
|
||||
"CONFIG_64",
|
||||
"Py_BUILD_CORE"
|
||||
],
|
||||
"C_Cpp.default.includePath": [
|
||||
"${workspaceFolder}/*",
|
||||
"${workspaceFolder}/Include/**"
|
||||
],
|
||||
// https://github.com/microsoft/vscode-cpptools/issues/10732
|
||||
"C_Cpp.errorSquiggles": "disabled",
|
||||
"editor.insertSpaces": true,
|
||||
"editor.rulers": [
|
||||
80
|
||||
],
|
||||
"editor.tabSize": 4,
|
||||
"editor.trimAutoWhitespace": true,
|
||||
"files.associations": {
|
||||
"*.h": "c"
|
||||
},
|
||||
"files.encoding": "utf8",
|
||||
"files.eol": "\n",
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"python.analysis.diagnosticSeverityOverrides": {
|
||||
// Complains about shadowing the stdlib w/ the stdlib.
|
||||
"reportShadowedImports": "none",
|
||||
// Doesn't like _frozen_importlib.
|
||||
"reportMissingImports": "none"
|
||||
},
|
||||
"python.analysis.extraPaths": [
|
||||
"Lib"
|
||||
],
|
||||
"[restructuredtext]": {
|
||||
"editor.tabSize": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
5
.gitattributes
vendored
5
.gitattributes
vendored
|
|
@ -68,7 +68,6 @@ PCbuild/readme.txt dos
|
|||
**/clinic/*.cpp.h generated
|
||||
**/clinic/*.h.h generated
|
||||
*_db.h generated
|
||||
Doc/_static/tachyon-example-*.html generated
|
||||
Doc/c-api/lifecycle.dot.svg generated
|
||||
Doc/data/stable_abi.dat generated
|
||||
Doc/library/token-list.inc generated
|
||||
|
|
@ -83,15 +82,11 @@ Include/opcode.h generated
|
|||
Include/opcode_ids.h generated
|
||||
Include/token.h generated
|
||||
Lib/_opcode_metadata.py generated
|
||||
Lib/idlelib/help.html generated
|
||||
Lib/keyword.py generated
|
||||
Lib/pydoc_data/topics.py generated
|
||||
Lib/pydoc_data/module_docs.py generated
|
||||
Lib/test/certdata/*.pem generated
|
||||
Lib/test/certdata/*.0 generated
|
||||
Lib/test/levenshtein_examples.json generated
|
||||
Lib/test/test_stable_abi_ctypes.py generated
|
||||
Lib/test/test_zoneinfo/data/*.json generated
|
||||
Lib/token.py generated
|
||||
Misc/sbom.spdx.json generated
|
||||
Objects/typeslots.inc generated
|
||||
|
|
|
|||
14
.github/CODEOWNERS
vendored
14
.github/CODEOWNERS
vendored
|
|
@ -126,9 +126,6 @@ Doc/howto/clinic.rst @erlend-aasland @AA-Turner
|
|||
# C Analyser
|
||||
Tools/c-analyzer/ @ericsnowcurrently
|
||||
|
||||
# C API Documentation Checks
|
||||
Tools/check-c-api-docs/ @ZeroIntensity
|
||||
|
||||
# Fuzzing
|
||||
Modules/_xxtestfuzz/ @ammaraskar
|
||||
|
||||
|
|
@ -289,10 +286,10 @@ Tools/jit/ @brandtbucher @savannahostrowski @diegorusso
|
|||
InternalDocs/jit.md @brandtbucher @savannahostrowski @diegorusso @AA-Turner
|
||||
|
||||
# Micro-op / μop / Tier 2 Optimiser
|
||||
Python/optimizer.c @markshannon @Fidget-Spinner
|
||||
Python/optimizer.c @markshannon
|
||||
Python/optimizer_analysis.c @markshannon @tomasr8 @Fidget-Spinner
|
||||
Python/optimizer_bytecodes.c @markshannon @tomasr8 @Fidget-Spinner
|
||||
Python/optimizer_symbols.c @markshannon @tomasr8 @Fidget-Spinner
|
||||
Python/optimizer_symbols.c @markshannon @tomasr8
|
||||
|
||||
# Parser, Lexer, and Grammar
|
||||
Grammar/python.gram @pablogsal @lysnikolaou
|
||||
|
|
@ -322,7 +319,7 @@ Tools/build/generate_global_objects.py @ericsnowcurrently
|
|||
# Remote Debugging
|
||||
Python/remote_debug.h @pablogsal
|
||||
Python/remote_debugging.c @pablogsal
|
||||
Modules/_remote_debugging/ @pablogsal
|
||||
Modules/_remote_debugging_module.c @pablogsal @ambv @1st1
|
||||
|
||||
# Sub-Interpreters
|
||||
**/*crossinterp* @ericsnowcurrently
|
||||
|
|
@ -537,11 +534,6 @@ Lib/pydoc.py @AA-Turner
|
|||
Lib/pydoc_data/ @AA-Turner
|
||||
Lib/test/test_pydoc/ @AA-Turner
|
||||
|
||||
# Profiling (Sampling)
|
||||
Doc/library/profiling*.rst @pablogsal
|
||||
Lib/profiling/ @pablogsal
|
||||
Lib/test/test_profiling/ @pablogsal
|
||||
|
||||
# PyREPL
|
||||
Lib/_pyrepl/ @pablogsal @lysnikolaou @ambv
|
||||
Lib/test/test_pyrepl/ @pablogsal @lysnikolaou @ambv
|
||||
|
|
|
|||
11
.github/CONTRIBUTING.rst
vendored
11
.github/CONTRIBUTING.rst
vendored
|
|
@ -28,12 +28,13 @@ Please be aware that our workflow does deviate slightly from the typical GitHub
|
|||
project. Details on how to properly submit a pull request are covered in
|
||||
`Lifecycle of a Pull Request <https://devguide.python.org/getting-started/pull-request-lifecycle.html>`_.
|
||||
We utilize various bots and status checks to help with this, so do follow the
|
||||
comments they leave and their "Details" links, respectively.
|
||||
comments they leave and their "Details" links, respectively. The key points of
|
||||
our workflow that are not covered by a bot or status check are:
|
||||
|
||||
The final key part of our workflow is that all discussions that are not
|
||||
directly related to the code in the pull request should happen on
|
||||
`GitHub Issues <https://github.com/python/cpython/issues>`__, generally in the
|
||||
pull request's parent issue.
|
||||
- All discussions that are not directly related to the code in the pull request
|
||||
should happen on `GitHub Issues <https://github.com/python/cpython/issues>`_.
|
||||
- Upon your first non-trivial pull request (which includes documentation changes),
|
||||
feel free to add yourself to ``Misc/ACKS``.
|
||||
|
||||
|
||||
Setting Expectations
|
||||
|
|
|
|||
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -5,6 +5,3 @@ contact_links:
|
|||
- name: "Proposing new features"
|
||||
about: "Submit major feature proposal (e.g. syntax changes) to an ideas forum first."
|
||||
url: "https://discuss.python.org/c/ideas/6"
|
||||
- name: "Python Install Manager issues"
|
||||
about: "Report issues with the Python Install Manager (for Windows)"
|
||||
url: "https://github.com/python/pymanager/issues"
|
||||
|
|
|
|||
7
.github/dependabot.yml
vendored
7
.github/dependabot.yml
vendored
|
|
@ -12,11 +12,6 @@ updates:
|
|||
update-types:
|
||||
- "version-update:semver-minor"
|
||||
- "version-update:semver-patch"
|
||||
cooldown:
|
||||
# https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns
|
||||
# Cooldowns protect against supply chain attacks by avoiding the
|
||||
# highest-risk window immediately after new releases.
|
||||
default-days: 14
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/Tools/"
|
||||
schedule:
|
||||
|
|
@ -24,5 +19,3 @@ updates:
|
|||
labels:
|
||||
- "skip issue"
|
||||
- "skip news"
|
||||
cooldown:
|
||||
default-days: 14
|
||||
|
|
|
|||
141
.github/workflows/build.yml
vendored
141
.github/workflows/build.yml
vendored
|
|
@ -109,10 +109,20 @@ jobs:
|
|||
python-version: '3.x'
|
||||
- name: Runner image version
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: Restore config.cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: config.cache
|
||||
# Include env.pythonLocation in key to avoid changes in environment when setup-python updates Python
|
||||
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }}-${{ env.pythonLocation }}
|
||||
- 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 ccache action
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
save: false
|
||||
- name: Configure CPython
|
||||
run: |
|
||||
# Build Python with the libpython dynamic library
|
||||
|
|
@ -142,9 +152,6 @@ jobs:
|
|||
- name: Check for unsupported C global variables
|
||||
if: github.event_name == 'pull_request' # $GITHUB_EVENT_NAME
|
||||
run: make check-c-globals
|
||||
- name: Check for undocumented C APIs
|
||||
run: make check-c-api-docs
|
||||
|
||||
|
||||
build-windows:
|
||||
name: >-
|
||||
|
|
@ -191,7 +198,7 @@ jobs:
|
|||
macOS
|
||||
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
|
||||
needs: build-context
|
||||
if: needs.build-context.outputs.run-macos == 'true'
|
||||
if: needs.build-context.outputs.run-tests == 'true'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -208,6 +215,7 @@ jobs:
|
|||
free-threading: true
|
||||
uses: ./.github/workflows/reusable-macos.yml
|
||||
with:
|
||||
config_hash: ${{ needs.build-context.outputs.config-hash }}
|
||||
free-threading: ${{ matrix.free-threading }}
|
||||
os: ${{ matrix.os }}
|
||||
|
||||
|
|
@ -217,7 +225,7 @@ jobs:
|
|||
${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
|
||||
${{ fromJSON(matrix.bolt) && '(bolt)' || '' }}
|
||||
needs: build-context
|
||||
if: needs.build-context.outputs.run-ubuntu == 'true'
|
||||
if: needs.build-context.outputs.run-tests == 'true'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -239,6 +247,7 @@ jobs:
|
|||
bolt: true
|
||||
uses: ./.github/workflows/reusable-ubuntu.yml
|
||||
with:
|
||||
config_hash: ${{ needs.build-context.outputs.config-hash }}
|
||||
bolt-optimizations: ${{ matrix.bolt }}
|
||||
free-threading: ${{ matrix.free-threading }}
|
||||
os: ${{ matrix.os }}
|
||||
|
|
@ -248,7 +257,7 @@ jobs:
|
|||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
needs: build-context
|
||||
if: needs.build-context.outputs.run-ubuntu == 'true'
|
||||
if: needs.build-context.outputs.run-tests == 'true'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -269,6 +278,11 @@ jobs:
|
|||
persist-credentials: false
|
||||
- name: Runner image version
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: Restore config.cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: config.cache
|
||||
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }}
|
||||
- name: Register gcc problem matcher
|
||||
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
|
||||
- name: Install dependencies
|
||||
|
|
@ -290,6 +304,10 @@ jobs:
|
|||
- name: Add ccache to PATH
|
||||
run: |
|
||||
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: Configure ccache action
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
save: false
|
||||
- name: Configure CPython
|
||||
run: ./configure CFLAGS="-fdiagnostics-format=json" --config-cache --enable-slower-safety --with-pydebug --with-openssl="$OPENSSL_DIR"
|
||||
- name: Build CPython
|
||||
|
|
@ -304,7 +322,7 @@ jobs:
|
|||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
needs: build-context
|
||||
if: needs.build-context.outputs.run-ubuntu == 'true'
|
||||
if: needs.build-context.outputs.run-tests == 'true'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -321,6 +339,11 @@ jobs:
|
|||
persist-credentials: false
|
||||
- name: Runner image version
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: Restore config.cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: config.cache
|
||||
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }}
|
||||
- name: Register gcc problem matcher
|
||||
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
|
||||
- name: Install dependencies
|
||||
|
|
@ -347,6 +370,10 @@ jobs:
|
|||
- name: Add ccache to PATH
|
||||
run: |
|
||||
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: Configure ccache action
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
save: false
|
||||
- name: Configure CPython
|
||||
run: |
|
||||
./configure CFLAGS="-fdiagnostics-format=json" \
|
||||
|
|
@ -368,7 +395,7 @@ jobs:
|
|||
build-android:
|
||||
name: Android (${{ matrix.arch }})
|
||||
needs: build-context
|
||||
if: needs.build-context.outputs.run-android == 'true'
|
||||
if: needs.build-context.outputs.run-tests == 'true'
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
@ -387,41 +414,20 @@ jobs:
|
|||
- name: Build and test
|
||||
run: ./Android/android.py ci --fast-ci ${{ matrix.arch }}-linux-android
|
||||
|
||||
build-ios:
|
||||
name: iOS
|
||||
needs: build-context
|
||||
if: needs.build-context.outputs.run-ios == 'true'
|
||||
timeout-minutes: 60
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
# GitHub recommends explicitly selecting the desired Xcode version:
|
||||
# https://github.com/actions/runner-images/issues/12541#issuecomment-3083850140
|
||||
# This became a necessity as a result of
|
||||
# https://github.com/actions/runner-images/issues/12541 and
|
||||
# https://github.com/actions/runner-images/issues/12751.
|
||||
- name: Select Xcode version
|
||||
run: |
|
||||
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'
|
||||
|
||||
build-wasi:
|
||||
name: 'WASI'
|
||||
needs: build-context
|
||||
if: needs.build-context.outputs.run-wasi == 'true'
|
||||
if: needs.build-context.outputs.run-tests == 'true'
|
||||
uses: ./.github/workflows/reusable-wasi.yml
|
||||
with:
|
||||
config_hash: ${{ needs.build-context.outputs.config-hash }}
|
||||
|
||||
test-hypothesis:
|
||||
name: "Hypothesis tests on Ubuntu"
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
needs: build-context
|
||||
if: needs.build-context.outputs.run-ubuntu == 'true'
|
||||
if: needs.build-context.outputs.run-tests == 'true'
|
||||
env:
|
||||
OPENSSL_VER: 3.0.18
|
||||
PYTHONSTRICTEXTENSIONBUILD: 1
|
||||
|
|
@ -450,6 +456,10 @@ jobs:
|
|||
- name: Add ccache to PATH
|
||||
run: |
|
||||
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: Configure ccache action
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
save: false
|
||||
- name: Setup directory envs for out-of-tree builds
|
||||
run: |
|
||||
echo "CPYTHON_RO_SRCDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-ro-srcdir)" >> "$GITHUB_ENV"
|
||||
|
|
@ -460,6 +470,11 @@ jobs:
|
|||
run: sudo mount --bind -o ro "$GITHUB_WORKSPACE" "$CPYTHON_RO_SRCDIR"
|
||||
- name: Runner image version
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: Restore config.cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.CPYTHON_BUILDDIR }}/config.cache
|
||||
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }}
|
||||
- name: Configure CPython out-of-tree
|
||||
working-directory: ${{ env.CPYTHON_BUILDDIR }}
|
||||
run: |
|
||||
|
|
@ -528,7 +543,7 @@ jobs:
|
|||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
needs: build-context
|
||||
if: needs.build-context.outputs.run-ubuntu == 'true'
|
||||
if: needs.build-context.outputs.run-tests == 'true'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -543,6 +558,11 @@ jobs:
|
|||
persist-credentials: false
|
||||
- name: Runner image version
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: Restore config.cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: config.cache
|
||||
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }}
|
||||
- name: Register gcc problem matcher
|
||||
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
|
||||
- name: Install dependencies
|
||||
|
|
@ -568,6 +588,11 @@ jobs:
|
|||
- name: Add ccache to PATH
|
||||
run: |
|
||||
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: Configure ccache action
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
save: ${{ github.event_name == 'push' }}
|
||||
max-size: "200M"
|
||||
- name: Configure CPython
|
||||
run: ./configure --config-cache --with-address-sanitizer --without-pymalloc
|
||||
- name: Build CPython
|
||||
|
|
@ -581,7 +606,7 @@ jobs:
|
|||
# ${{ '' } is a hack to nest jobs under the same sidebar category.
|
||||
name: Sanitizers${{ '' }} # zizmor: ignore[obfuscation]
|
||||
needs: build-context
|
||||
if: needs.build-context.outputs.run-ubuntu == 'true'
|
||||
if: needs.build-context.outputs.run-tests == 'true'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -599,6 +624,7 @@ jobs:
|
|||
uses: ./.github/workflows/reusable-san.yml
|
||||
with:
|
||||
sanitizer: ${{ matrix.sanitizer }}
|
||||
config_hash: ${{ needs.build-context.outputs.config-hash }}
|
||||
free-threading: ${{ matrix.free-threading }}
|
||||
|
||||
cross-build-linux:
|
||||
|
|
@ -606,13 +632,18 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
needs: build-context
|
||||
if: needs.build-context.outputs.run-ubuntu == 'true'
|
||||
if: needs.build-context.outputs.run-tests == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Runner image version
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: Restore config.cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: config.cache
|
||||
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }}
|
||||
- name: Register gcc problem matcher
|
||||
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
|
||||
- name: Set build dir
|
||||
|
|
@ -692,7 +723,6 @@ jobs:
|
|||
- build-ubuntu-ssltests-awslc
|
||||
- build-ubuntu-ssltests-openssl
|
||||
- build-android
|
||||
- build-ios
|
||||
- build-wasi
|
||||
- test-hypothesis
|
||||
- build-asan
|
||||
|
|
@ -712,24 +742,24 @@ jobs:
|
|||
test-hypothesis,
|
||||
cifuzz,
|
||||
allowed-skips: >-
|
||||
${{ !fromJSON(needs.build-context.outputs.run-docs) && 'check-docs,' || '' }}
|
||||
${{
|
||||
!fromJSON(needs.build-context.outputs.run-docs)
|
||||
&& '
|
||||
check-docs,
|
||||
'
|
||||
|| ''
|
||||
}}
|
||||
${{
|
||||
needs.build-context.outputs.run-tests != 'true'
|
||||
&& '
|
||||
check-autoconf-regen,
|
||||
check-generated-files,
|
||||
'
|
||||
|| ''
|
||||
}}
|
||||
${{ !fromJSON(needs.build-context.outputs.run-windows-tests) && 'build-windows,' || '' }}
|
||||
${{ !fromJSON(needs.build-context.outputs.run-ci-fuzz) && 'cifuzz,' || '' }}
|
||||
${{ !fromJSON(needs.build-context.outputs.run-macos) && 'build-macos,' || '' }}
|
||||
${{
|
||||
!fromJSON(needs.build-context.outputs.run-ubuntu)
|
||||
&& '
|
||||
build-macos,
|
||||
build-ubuntu,
|
||||
build-ubuntu-ssltests-awslc,
|
||||
build-ubuntu-ssltests-openssl,
|
||||
build-android,
|
||||
build-wasi,
|
||||
test-hypothesis,
|
||||
build-asan,
|
||||
build-san,
|
||||
|
|
@ -737,7 +767,18 @@ 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-wasi) && 'build-wasi,' || '' }}
|
||||
${{
|
||||
!fromJSON(needs.build-context.outputs.run-windows-tests)
|
||||
&& '
|
||||
build-windows,
|
||||
'
|
||||
|| ''
|
||||
}}
|
||||
${{
|
||||
!fromJSON(needs.build-context.outputs.run-ci-fuzz)
|
||||
&& '
|
||||
cifuzz,
|
||||
'
|
||||
|| ''
|
||||
}}
|
||||
jobs: ${{ toJSON(needs) }}
|
||||
|
|
|
|||
30
.github/workflows/jit.yml
vendored
30
.github/workflows/jit.yml
vendored
|
|
@ -68,7 +68,7 @@ jobs:
|
|||
- true
|
||||
- false
|
||||
llvm:
|
||||
- 21
|
||||
- 19
|
||||
include:
|
||||
- target: i686-pc-windows-msvc/msvc
|
||||
architecture: Win32
|
||||
|
|
@ -138,7 +138,7 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
llvm:
|
||||
- 21
|
||||
- 19
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
|
@ -166,7 +166,7 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
llvm:
|
||||
- 21
|
||||
- 19
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
|
@ -183,27 +183,3 @@ jobs:
|
|||
- name: Run tests without optimizations
|
||||
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@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v5
|
||||
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
|
||||
|
|
|
|||
3
.github/workflows/mypy.yml
vendored
3
.github/workflows/mypy.yml
vendored
|
|
@ -16,7 +16,6 @@ on:
|
|||
- "Tools/build/check_extension_modules.py"
|
||||
- "Tools/build/check_warnings.py"
|
||||
- "Tools/build/compute-changes.py"
|
||||
- "Tools/build/consts_getter.py"
|
||||
- "Tools/build/deepfreeze.py"
|
||||
- "Tools/build/generate-build-details.py"
|
||||
- "Tools/build/generate_sbom.py"
|
||||
|
|
@ -26,7 +25,6 @@ on:
|
|||
- "Tools/build/update_file.py"
|
||||
- "Tools/build/verify_ensurepip_wheels.py"
|
||||
- "Tools/cases_generator/**"
|
||||
- "Tools/check-c-api-docs/**"
|
||||
- "Tools/clinic/**"
|
||||
- "Tools/jit/**"
|
||||
- "Tools/peg_generator/**"
|
||||
|
|
@ -59,7 +57,6 @@ jobs:
|
|||
"Lib/tomllib",
|
||||
"Tools/build",
|
||||
"Tools/cases_generator",
|
||||
"Tools/check-c-api-docs",
|
||||
"Tools/clinic",
|
||||
"Tools/jit",
|
||||
"Tools/peg_generator",
|
||||
|
|
|
|||
41
.github/workflows/reusable-context.yml
vendored
41
.github/workflows/reusable-context.yml
vendored
|
|
@ -17,36 +17,24 @@ on: # yamllint disable-line rule:truthy
|
|||
# || 'falsy-branch'
|
||||
# }}
|
||||
#
|
||||
run-android:
|
||||
description: Whether to run the Android tests
|
||||
value: ${{ jobs.compute-changes.outputs.run-android }} # bool
|
||||
run-ci-fuzz:
|
||||
description: Whether to run the CIFuzz job
|
||||
value: ${{ jobs.compute-changes.outputs.run-ci-fuzz }} # bool
|
||||
config-hash:
|
||||
description: Config hash value for use in cache keys
|
||||
value: ${{ jobs.compute-changes.outputs.config-hash }} # str
|
||||
run-docs:
|
||||
description: Whether to build the docs
|
||||
value: ${{ jobs.compute-changes.outputs.run-docs }} # bool
|
||||
run-ios:
|
||||
description: Whether to run the iOS tests
|
||||
value: ${{ jobs.compute-changes.outputs.run-ios }} # bool
|
||||
run-macos:
|
||||
description: Whether to run the macOS tests
|
||||
value: ${{ jobs.compute-changes.outputs.run-macos }} # bool
|
||||
run-tests:
|
||||
description: Whether to run the regular tests
|
||||
value: ${{ jobs.compute-changes.outputs.run-tests }} # bool
|
||||
run-ubuntu:
|
||||
description: Whether to run the Ubuntu tests
|
||||
value: ${{ jobs.compute-changes.outputs.run-ubuntu }} # bool
|
||||
run-wasi:
|
||||
description: Whether to run the WASI tests
|
||||
value: ${{ jobs.compute-changes.outputs.run-wasi }} # bool
|
||||
run-windows-msi:
|
||||
description: Whether to run the MSI installer smoke tests
|
||||
value: ${{ jobs.compute-changes.outputs.run-windows-msi }} # bool
|
||||
run-windows-tests:
|
||||
description: Whether to run the Windows tests
|
||||
value: ${{ jobs.compute-changes.outputs.run-windows-tests }} # bool
|
||||
run-windows-msi:
|
||||
description: Whether to run the MSI installer smoke tests
|
||||
value: ${{ jobs.compute-changes.outputs.run-windows-msi }} # bool
|
||||
run-ci-fuzz:
|
||||
description: Whether to run the CIFuzz job
|
||||
value: ${{ jobs.compute-changes.outputs.run-ci-fuzz }} # bool
|
||||
|
||||
jobs:
|
||||
compute-changes:
|
||||
|
|
@ -54,14 +42,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
outputs:
|
||||
run-android: ${{ steps.changes.outputs.run-android }}
|
||||
config-hash: ${{ steps.config-hash.outputs.hash }}
|
||||
run-ci-fuzz: ${{ steps.changes.outputs.run-ci-fuzz }}
|
||||
run-docs: ${{ steps.changes.outputs.run-docs }}
|
||||
run-ios: ${{ steps.changes.outputs.run-ios }}
|
||||
run-macos: ${{ steps.changes.outputs.run-macos }}
|
||||
run-tests: ${{ steps.changes.outputs.run-tests }}
|
||||
run-ubuntu: ${{ steps.changes.outputs.run-ubuntu }}
|
||||
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:
|
||||
|
|
@ -116,3 +100,8 @@ jobs:
|
|||
GITHUB_EVENT_NAME: ${{ github.event_name }}
|
||||
CCF_TARGET_REF: ${{ github.base_ref || github.event.repository.default_branch }}
|
||||
CCF_HEAD_REF: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Compute hash for config cache key
|
||||
id: config-hash
|
||||
run: |
|
||||
echo "hash=${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }}" >> "$GITHUB_OUTPUT"
|
||||
|
|
|
|||
8
.github/workflows/reusable-macos.yml
vendored
8
.github/workflows/reusable-macos.yml
vendored
|
|
@ -3,6 +3,9 @@ name: Reusable macOS
|
|||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
config_hash:
|
||||
required: true
|
||||
type: string
|
||||
free-threading:
|
||||
required: false
|
||||
type: boolean
|
||||
|
|
@ -33,6 +36,11 @@ jobs:
|
|||
persist-credentials: false
|
||||
- name: Runner image version
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: Restore config.cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: config.cache
|
||||
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ inputs.config_hash }}
|
||||
- name: Install Homebrew dependencies
|
||||
run: |
|
||||
brew install pkg-config openssl@3.0 xz gdbm tcl-tk@9 make
|
||||
|
|
|
|||
13
.github/workflows/reusable-san.yml
vendored
13
.github/workflows/reusable-san.yml
vendored
|
|
@ -6,6 +6,9 @@ on:
|
|||
sanitizer:
|
||||
required: true
|
||||
type: string
|
||||
config_hash:
|
||||
required: true
|
||||
type: string
|
||||
free-threading:
|
||||
description: Whether to use free-threaded mode
|
||||
required: false
|
||||
|
|
@ -31,6 +34,11 @@ jobs:
|
|||
persist-credentials: false
|
||||
- name: Runner image version
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: Restore config.cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: config.cache
|
||||
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ inputs.sanitizer }}-${{ inputs.config_hash }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo ./.github/workflows/posix-deps-apt.sh
|
||||
|
|
@ -69,6 +77,11 @@ jobs:
|
|||
- name: Add ccache to PATH
|
||||
run: |
|
||||
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: Configure ccache action
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
save: ${{ github.event_name == 'push' }}
|
||||
max-size: "200M"
|
||||
- name: Configure CPython
|
||||
run: >-
|
||||
./configure
|
||||
|
|
|
|||
13
.github/workflows/reusable-ubuntu.yml
vendored
13
.github/workflows/reusable-ubuntu.yml
vendored
|
|
@ -3,6 +3,9 @@ name: Reusable Ubuntu
|
|||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
config_hash:
|
||||
required: true
|
||||
type: string
|
||||
bolt-optimizations:
|
||||
description: Whether to enable BOLT optimizations
|
||||
required: false
|
||||
|
|
@ -61,6 +64,11 @@ jobs:
|
|||
- name: Add ccache to PATH
|
||||
run: |
|
||||
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: Configure ccache action
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
save: ${{ github.event_name == 'push' }}
|
||||
max-size: "200M"
|
||||
- name: Setup directory envs for out-of-tree builds
|
||||
run: |
|
||||
echo "CPYTHON_RO_SRCDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-ro-srcdir)" >> "$GITHUB_ENV"
|
||||
|
|
@ -71,6 +79,11 @@ jobs:
|
|||
run: sudo mount --bind -o ro "$GITHUB_WORKSPACE" "$CPYTHON_RO_SRCDIR"
|
||||
- name: Runner image version
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: Restore config.cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.CPYTHON_BUILDDIR }}/config.cache
|
||||
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ inputs.config_hash }}
|
||||
- name: Configure CPython out-of-tree
|
||||
working-directory: ${{ env.CPYTHON_BUILDDIR }}
|
||||
# `test_unpickle_module_race` writes to the source directory, which is
|
||||
|
|
|
|||
39
.github/workflows/reusable-wasi.yml
vendored
39
.github/workflows/reusable-wasi.yml
vendored
|
|
@ -2,6 +2,10 @@ name: Reusable WASI
|
|||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
config_hash:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
|
@ -9,11 +13,11 @@ env:
|
|||
jobs:
|
||||
build-wasi-reusable:
|
||||
name: 'build and test'
|
||||
runs-on: ubuntu-24.04-arm
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
WASMTIME_VERSION: 38.0.3
|
||||
WASI_SDK_VERSION: 29
|
||||
WASMTIME_VERSION: 22.0.0
|
||||
WASI_SDK_VERSION: 24
|
||||
WASI_SDK_PATH: /opt/wasi-sdk
|
||||
CROSS_BUILD_PYTHON: cross-build/build
|
||||
CROSS_BUILD_WASI: cross-build/wasm32-wasip1
|
||||
|
|
@ -36,8 +40,13 @@ jobs:
|
|||
if: steps.cache-wasi-sdk.outputs.cache-hit != 'true'
|
||||
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" | \
|
||||
curl -s -S --location "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_VERSION}.0-x86_64-linux.tar.gz" | \
|
||||
tar --strip-components 1 --directory "${WASI_SDK_PATH}" --extract --gunzip
|
||||
- name: "Configure ccache action"
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
save: ${{ github.event_name == 'push' }}
|
||||
max-size: "200M"
|
||||
- name: "Add ccache to PATH"
|
||||
run: echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
|
||||
- name: "Install Python"
|
||||
|
|
@ -46,15 +55,29 @@ jobs:
|
|||
python-version: '3.x'
|
||||
- name: "Runner image version"
|
||||
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
|
||||
- name: "Restore Python build config.cache"
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.CROSS_BUILD_PYTHON }}/config.cache
|
||||
# Include env.pythonLocation in key to avoid changes in environment when setup-python updates Python.
|
||||
# Include the hash of `Tools/wasm/wasi.py` as it may change the environment variables.
|
||||
# (Make sure to keep the key in sync with the other config.cache step below.)
|
||||
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ env.WASI_SDK_VERSION }}-${{ env.WASMTIME_VERSION }}-${{ inputs.config_hash }}-${{ hashFiles('Tools/wasm/wasi.py') }}-${{ env.pythonLocation }}
|
||||
- name: "Configure build Python"
|
||||
run: python3 Tools/wasm/wasi configure-build-python -- --config-cache --with-pydebug
|
||||
run: python3 Tools/wasm/wasi.py configure-build-python -- --config-cache --with-pydebug
|
||||
- name: "Make build Python"
|
||||
run: python3 Tools/wasm/wasi make-build-python
|
||||
run: python3 Tools/wasm/wasi.py make-build-python
|
||||
- name: "Restore host config.cache"
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.CROSS_BUILD_WASI }}/config.cache
|
||||
# Should be kept in sync with the other config.cache step above.
|
||||
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ env.WASI_SDK_VERSION }}-${{ env.WASMTIME_VERSION }}-${{ inputs.config_hash }}-${{ hashFiles('Tools/wasm/wasi.py') }}-${{ env.pythonLocation }}
|
||||
- name: "Configure host"
|
||||
# `--with-pydebug` inferred from configure-build-python
|
||||
run: python3 Tools/wasm/wasi configure-host -- --config-cache
|
||||
run: python3 Tools/wasm/wasi.py configure-host -- --config-cache
|
||||
- name: "Make host"
|
||||
run: python3 Tools/wasm/wasi make-host
|
||||
run: python3 Tools/wasm/wasi.py make-host
|
||||
- name: "Display build info"
|
||||
run: make --directory "${CROSS_BUILD_WASI}" pythoninfo
|
||||
- name: "Test"
|
||||
|
|
|
|||
14
.github/workflows/tail-call.yml
vendored
14
.github/workflows/tail-call.yml
vendored
|
|
@ -79,17 +79,19 @@ jobs:
|
|||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Native Windows MSVC (release)
|
||||
- name: Native Windows (debug)
|
||||
if: runner.os == 'Windows' && matrix.architecture != 'ARM64'
|
||||
shell: cmd
|
||||
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"
|
||||
./PCbuild/build.bat --tail-call-interp -c Release -p ${{ matrix.architecture }} "/p:PlatformToolset=v145"
|
||||
./PCbuild/rt.bat -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
|
||||
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
|
||||
set PlatformToolset=clangcl
|
||||
set LLVMToolsVersion=${{ matrix.llvm }}.1.0
|
||||
set LLVMInstallDir=C:\Program Files\LLVM
|
||||
call ./PCbuild/build.bat --tail-call-interp -d -p ${{ matrix.architecture }}
|
||||
call ./PCbuild/rt.bat -d -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
|
||||
|
||||
# No tests (yet):
|
||||
- name: Emulated Windows Clang (release)
|
||||
- name: Emulated Windows (release)
|
||||
if: runner.os == 'Windows' && matrix.architecture == 'ARM64'
|
||||
shell: cmd
|
||||
run: |
|
||||
|
|
|
|||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -45,7 +45,6 @@ gmon.out
|
|||
.pytest_cache/
|
||||
.ruff_cache/
|
||||
.DS_Store
|
||||
.pixi/
|
||||
|
||||
*.exe
|
||||
|
||||
|
|
@ -136,6 +135,7 @@ Tools/unicode/data/
|
|||
/config.log
|
||||
/config.status
|
||||
/config.status.lineno
|
||||
# hendrikmuhs/ccache-action@v1
|
||||
/.ccache
|
||||
/cross-build/
|
||||
/jit_stencils*.h
|
||||
|
|
|
|||
|
|
@ -2,10 +2,6 @@ repos:
|
|||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.13.2
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
name: Run Ruff (lint) on Apple/
|
||||
args: [--exit-non-zero-on-fix, --config=Apple/.ruff.toml]
|
||||
files: ^Apple/
|
||||
- id: ruff-check
|
||||
name: Run Ruff (lint) on Doc/
|
||||
args: [--exit-non-zero-on-fix]
|
||||
|
|
@ -34,21 +30,17 @@ repos:
|
|||
name: Run Ruff (lint) on Tools/wasm/
|
||||
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
|
||||
- id: ruff-format
|
||||
name: Run Ruff (format) on Doc/
|
||||
args: [--exit-non-zero-on-fix]
|
||||
args: [--check]
|
||||
files: ^Doc/
|
||||
- id: ruff-format
|
||||
name: Run Ruff (format) on Tools/build/check_warnings.py
|
||||
args: [--exit-non-zero-on-fix, --config=Tools/build/.ruff.toml]
|
||||
args: [--check, --config=Tools/build/.ruff.toml]
|
||||
files: ^Tools/build/check_warnings.py
|
||||
- id: ruff-format
|
||||
name: Run Ruff (format) on Tools/wasm/
|
||||
args: [--exit-non-zero-on-fix, --config=Tools/wasm/.ruff.toml]
|
||||
args: [--check, --config=Tools/wasm/.ruff.toml]
|
||||
files: ^Tools/wasm/
|
||||
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ in_source_tree = (
|
|||
ANDROID_DIR.name == "Android" and (PYTHON_DIR / "pyconfig.h.in").exists()
|
||||
)
|
||||
|
||||
ENV_SCRIPT = ANDROID_DIR / "android-env.sh"
|
||||
TESTBED_DIR = ANDROID_DIR / "testbed"
|
||||
CROSS_BUILD_DIR = PYTHON_DIR / "cross-build"
|
||||
|
||||
|
|
@ -130,11 +129,12 @@ def android_env(host):
|
|||
sysconfig_filename = next(sysconfig_files).name
|
||||
host = re.fullmatch(r"_sysconfigdata__android_(.+).py", sysconfig_filename)[1]
|
||||
|
||||
env_script = ANDROID_DIR / "android-env.sh"
|
||||
env_output = subprocess.run(
|
||||
f"set -eu; "
|
||||
f"HOST={host}; "
|
||||
f"PREFIX={prefix}; "
|
||||
f". {ENV_SCRIPT}; "
|
||||
f". {env_script}; "
|
||||
f"export",
|
||||
check=True, shell=True, capture_output=True, encoding='utf-8',
|
||||
).stdout
|
||||
|
|
@ -151,7 +151,7 @@ def android_env(host):
|
|||
env[key] = value
|
||||
|
||||
if not env:
|
||||
raise ValueError(f"Found no variables in {ENV_SCRIPT.name} output:\n"
|
||||
raise ValueError(f"Found no variables in {env_script.name} output:\n"
|
||||
+ env_output)
|
||||
return env
|
||||
|
||||
|
|
@ -281,30 +281,15 @@ def clean_all(context):
|
|||
|
||||
|
||||
def setup_ci():
|
||||
if "GITHUB_ACTIONS" in os.environ:
|
||||
# Enable emulator hardware acceleration
|
||||
# (https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/).
|
||||
if platform.system() == "Linux":
|
||||
run(
|
||||
["sudo", "tee", "/etc/udev/rules.d/99-kvm4all.rules"],
|
||||
input='KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"\n',
|
||||
text=True,
|
||||
)
|
||||
run(["sudo", "udevadm", "control", "--reload-rules"])
|
||||
run(["sudo", "udevadm", "trigger", "--name-match=kvm"])
|
||||
|
||||
# Free up disk space by deleting unused versions of the NDK
|
||||
# (https://github.com/freakboy3742/pyspamsum/pull/108).
|
||||
for line in ENV_SCRIPT.read_text().splitlines():
|
||||
if match := re.fullmatch(r"ndk_version=(.+)", line):
|
||||
ndk_version = match[1]
|
||||
break
|
||||
else:
|
||||
raise ValueError(f"Failed to find NDK version in {ENV_SCRIPT.name}")
|
||||
|
||||
for item in (android_home / "ndk").iterdir():
|
||||
if item.name[0].isdigit() and item.name != ndk_version:
|
||||
delete_glob(item)
|
||||
# https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/
|
||||
if "GITHUB_ACTIONS" in os.environ and platform.system() == "Linux":
|
||||
run(
|
||||
["sudo", "tee", "/etc/udev/rules.d/99-kvm4all.rules"],
|
||||
input='KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"\n',
|
||||
text=True,
|
||||
)
|
||||
run(["sudo", "udevadm", "control", "--reload-rules"])
|
||||
run(["sudo", "udevadm", "trigger", "--name-match=kvm"])
|
||||
|
||||
|
||||
def setup_sdk():
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ for ((i, prefix) in prefixes.withIndex()) {
|
|||
val libDir = file("$prefix/lib")
|
||||
val version = run {
|
||||
for (filename in libDir.list()!!) {
|
||||
"""python(\d+\.\d+[a-z]*)""".toRegex().matchEntire(filename)?.let {
|
||||
"""python(\d+\.\d+)""".toRegex().matchEntire(filename)?.let {
|
||||
return@run it.groupValues[1]
|
||||
}
|
||||
}
|
||||
|
|
@ -64,10 +64,9 @@ for ((i, prefix) in prefixes.withIndex()) {
|
|||
val libPythonDir = file("$libDir/python$pythonVersion")
|
||||
val triplet = run {
|
||||
for (filename in libPythonDir.list()!!) {
|
||||
"""_sysconfigdata_[a-z]*_android_(.+).py""".toRegex()
|
||||
.matchEntire(filename)?.let {
|
||||
return@run it.groupValues[1]
|
||||
}
|
||||
"""_sysconfigdata__android_(.+).py""".toRegex().matchEntire(filename)?.let {
|
||||
return@run it.groupValues[1]
|
||||
}
|
||||
}
|
||||
throw GradleException("Failed to find Python triplet in $libPythonDir")
|
||||
}
|
||||
|
|
@ -79,7 +78,7 @@ android {
|
|||
val androidEnvFile = file("../../android-env.sh").absoluteFile
|
||||
|
||||
namespace = "org.python.testbed"
|
||||
compileSdk = 35
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "org.python.testbed"
|
||||
|
|
@ -92,7 +91,7 @@ android {
|
|||
}
|
||||
throw GradleException("Failed to find API level in $androidEnvFile")
|
||||
}
|
||||
targetSdk = 35
|
||||
targetSdk = 34
|
||||
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
extend = "../.ruff.toml" # Inherit the project-wide settings
|
||||
|
||||
[format]
|
||||
preview = true
|
||||
docstring-code-format = true
|
||||
|
||||
[lint]
|
||||
select = [
|
||||
"C4", # flake8-comprehensions
|
||||
"E", # pycodestyle
|
||||
"F", # pyflakes
|
||||
"I", # isort
|
||||
"ISC", # flake8-implicit-str-concat
|
||||
"LOG", # flake8-logging
|
||||
"PGH", # pygrep-hooks
|
||||
"PT", # flake8-pytest-style
|
||||
"PYI", # flake8-pyi
|
||||
"RUF100", # Ban unused `# noqa` comments
|
||||
"UP", # pyupgrade
|
||||
"W", # pycodestyle
|
||||
"YTT", # flake8-2020
|
||||
]
|
||||
|
|
@ -46,12 +46,13 @@ import subprocess
|
|||
import sys
|
||||
import sysconfig
|
||||
import time
|
||||
from collections.abc import Callable, Sequence
|
||||
from collections.abc import Sequence
|
||||
from contextlib import contextmanager
|
||||
from datetime import datetime, timezone
|
||||
from os.path import basename, relpath
|
||||
from pathlib import Path
|
||||
from subprocess import CalledProcessError
|
||||
from typing import Callable
|
||||
|
||||
EnvironmentT = dict[str, str]
|
||||
ArgsT = Sequence[str | Path]
|
||||
|
|
@ -139,15 +140,17 @@ def print_env(env: EnvironmentT) -> None:
|
|||
def apple_env(host: str) -> EnvironmentT:
|
||||
"""Construct an Apple development environment for the given host."""
|
||||
env = {
|
||||
"PATH": ":".join([
|
||||
str(PYTHON_DIR / "Apple/iOS/Resources/bin"),
|
||||
str(subdir(host) / "prefix"),
|
||||
"/usr/bin",
|
||||
"/bin",
|
||||
"/usr/sbin",
|
||||
"/sbin",
|
||||
"/Library/Apple/usr/bin",
|
||||
]),
|
||||
"PATH": ":".join(
|
||||
[
|
||||
str(PYTHON_DIR / "Apple/iOS/Resources/bin"),
|
||||
str(subdir(host) / "prefix"),
|
||||
"/usr/bin",
|
||||
"/bin",
|
||||
"/usr/sbin",
|
||||
"/sbin",
|
||||
"/Library/Apple/usr/bin",
|
||||
]
|
||||
),
|
||||
}
|
||||
|
||||
return env
|
||||
|
|
@ -193,10 +196,14 @@ def clean(context: argparse.Namespace, target: str = "all") -> None:
|
|||
paths.append(target)
|
||||
|
||||
if target in {"all", "hosts", "test"}:
|
||||
paths.extend([
|
||||
path.name
|
||||
for path in CROSS_BUILD_DIR.glob(f"{context.platform}-testbed.*")
|
||||
])
|
||||
paths.extend(
|
||||
[
|
||||
path.name
|
||||
for path in CROSS_BUILD_DIR.glob(
|
||||
f"{context.platform}-testbed.*"
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
for path in paths:
|
||||
delete_path(path)
|
||||
|
|
@ -345,16 +352,18 @@ def download(url: str, target_dir: Path) -> Path:
|
|||
|
||||
out_path = target_path / basename(url)
|
||||
if not Path(out_path).is_file():
|
||||
run([
|
||||
"curl",
|
||||
"-Lf",
|
||||
"--retry",
|
||||
"5",
|
||||
"--retry-all-errors",
|
||||
"-o",
|
||||
out_path,
|
||||
url,
|
||||
])
|
||||
run(
|
||||
[
|
||||
"curl",
|
||||
"-Lf",
|
||||
"--retry",
|
||||
"5",
|
||||
"--retry-all-errors",
|
||||
"-o",
|
||||
out_path,
|
||||
url,
|
||||
]
|
||||
)
|
||||
else:
|
||||
print(f"Using cached version of {basename(url)}")
|
||||
return out_path
|
||||
|
|
@ -459,7 +468,8 @@ def package_version(prefix_path: Path) -> str:
|
|||
|
||||
|
||||
def lib_platform_files(dirname, names):
|
||||
"""A file filter that ignores platform-specific files in lib."""
|
||||
"""A file filter that ignores platform-specific files in the lib directory.
|
||||
"""
|
||||
path = Path(dirname)
|
||||
if (
|
||||
path.parts[-3] == "lib"
|
||||
|
|
@ -468,7 +478,7 @@ def lib_platform_files(dirname, names):
|
|||
):
|
||||
return names
|
||||
elif path.parts[-2] == "lib" and path.parts[-1].startswith("python"):
|
||||
ignored_names = {
|
||||
ignored_names = set(
|
||||
name
|
||||
for name in names
|
||||
if (
|
||||
|
|
@ -476,13 +486,7 @@ def lib_platform_files(dirname, names):
|
|||
or name.startswith("_sysconfig_vars_")
|
||||
or name == "build-details.json"
|
||||
)
|
||||
}
|
||||
elif path.parts[-1] == "lib":
|
||||
ignored_names = {
|
||||
name
|
||||
for name in names
|
||||
if name.startswith("libpython") and name.endswith(".dylib")
|
||||
}
|
||||
)
|
||||
else:
|
||||
ignored_names = set()
|
||||
|
||||
|
|
@ -495,9 +499,7 @@ def lib_non_platform_files(dirname, names):
|
|||
"""
|
||||
path = Path(dirname)
|
||||
if path.parts[-2] == "lib" and path.parts[-1].startswith("python"):
|
||||
return (
|
||||
set(names) - lib_platform_files(dirname, names) - {"lib-dynload"}
|
||||
)
|
||||
return set(names) - lib_platform_files(dirname, names) - {"lib-dynload"}
|
||||
else:
|
||||
return set()
|
||||
|
||||
|
|
@ -505,15 +507,14 @@ def lib_non_platform_files(dirname, names):
|
|||
def create_xcframework(platform: str) -> str:
|
||||
"""Build an XCframework from the component parts for the platform.
|
||||
|
||||
:return: The version number of the Python version that was packaged.
|
||||
:return: The version number of the Python verion that was packaged.
|
||||
"""
|
||||
package_path = CROSS_BUILD_DIR / platform
|
||||
try:
|
||||
package_path.mkdir()
|
||||
except FileExistsError:
|
||||
raise RuntimeError(
|
||||
f"{platform} XCframework already exists; do you need to run "
|
||||
"with --clean?"
|
||||
f"{platform} XCframework already exists; do you need to run with --clean?"
|
||||
) from None
|
||||
|
||||
frameworks = []
|
||||
|
|
@ -606,7 +607,7 @@ def create_xcframework(platform: str) -> str:
|
|||
print(f" - {slice_name} binaries")
|
||||
shutil.copytree(first_path / "bin", slice_path / "bin")
|
||||
|
||||
# Copy the include path (a symlink to the framework headers)
|
||||
# Copy the include path (this will be a symlink to the framework headers)
|
||||
print(f" - {slice_name} include files")
|
||||
shutil.copytree(
|
||||
first_path / "include",
|
||||
|
|
@ -620,12 +621,6 @@ def create_xcframework(platform: str) -> str:
|
|||
slice_framework / "Headers/pyconfig.h",
|
||||
)
|
||||
|
||||
print(f" - {slice_name} shared library")
|
||||
# Create a simlink for the fat library
|
||||
shared_lib = slice_path / f"lib/libpython{version_tag}.dylib"
|
||||
shared_lib.parent.mkdir()
|
||||
shared_lib.symlink_to("../Python.framework/Python")
|
||||
|
||||
print(f" - {slice_name} architecture-specific files")
|
||||
for host_triple, multiarch in slice_parts.items():
|
||||
print(f" - {multiarch} standard library")
|
||||
|
|
@ -637,7 +632,6 @@ def create_xcframework(platform: str) -> str:
|
|||
framework_path(host_triple, multiarch) / "lib",
|
||||
package_path / "Python.xcframework/lib",
|
||||
ignore=lib_platform_files,
|
||||
symlinks=True,
|
||||
)
|
||||
has_common_stdlib = True
|
||||
|
||||
|
|
@ -645,7 +639,6 @@ def create_xcframework(platform: str) -> str:
|
|||
framework_path(host_triple, multiarch) / "lib",
|
||||
slice_path / f"lib-{arch}",
|
||||
ignore=lib_non_platform_files,
|
||||
symlinks=True,
|
||||
)
|
||||
|
||||
# Copy the host's pyconfig.h to an architecture-specific name.
|
||||
|
|
@ -666,8 +659,7 @@ def create_xcframework(platform: str) -> str:
|
|||
# statically link those libraries into a Framework, you become
|
||||
# responsible for providing a privacy manifest for that framework.
|
||||
xcprivacy_file = {
|
||||
"OpenSSL": subdir(host_triple)
|
||||
/ "prefix/share/OpenSSL.xcprivacy"
|
||||
"OpenSSL": subdir(host_triple) / "prefix/share/OpenSSL.xcprivacy"
|
||||
}
|
||||
print(f" - {multiarch} xcprivacy files")
|
||||
for module, lib in [
|
||||
|
|
@ -677,8 +669,7 @@ def create_xcframework(platform: str) -> str:
|
|||
shutil.copy(
|
||||
xcprivacy_file[lib],
|
||||
slice_path
|
||||
/ f"lib-{arch}/python{version_tag}"
|
||||
/ f"lib-dynload/{module}.xcprivacy",
|
||||
/ f"lib-{arch}/python{version_tag}/lib-dynload/{module}.xcprivacy",
|
||||
)
|
||||
|
||||
print(" - build tools")
|
||||
|
|
@ -701,16 +692,18 @@ def package(context: argparse.Namespace) -> None:
|
|||
|
||||
# Clone testbed
|
||||
print()
|
||||
run([
|
||||
sys.executable,
|
||||
"Apple/testbed",
|
||||
"clone",
|
||||
"--platform",
|
||||
context.platform,
|
||||
"--framework",
|
||||
CROSS_BUILD_DIR / context.platform / "Python.xcframework",
|
||||
CROSS_BUILD_DIR / context.platform / "testbed",
|
||||
])
|
||||
run(
|
||||
[
|
||||
sys.executable,
|
||||
"Apple/testbed",
|
||||
"clone",
|
||||
"--platform",
|
||||
context.platform,
|
||||
"--framework",
|
||||
CROSS_BUILD_DIR / context.platform / "Python.xcframework",
|
||||
CROSS_BUILD_DIR / context.platform / "testbed",
|
||||
]
|
||||
)
|
||||
|
||||
# Build the final archive
|
||||
archive_name = (
|
||||
|
|
@ -764,7 +757,7 @@ def build(context: argparse.Namespace, host: str | None = None) -> None:
|
|||
package(context)
|
||||
|
||||
|
||||
def test(context: argparse.Namespace, host: str | None = None) -> None: # noqa: PT028
|
||||
def test(context: argparse.Namespace, host: str | None = None) -> None:
|
||||
"""The implementation of the "test" command."""
|
||||
if host is None:
|
||||
host = context.host
|
||||
|
|
@ -802,16 +795,18 @@ def test(context: argparse.Namespace, host: str | None = None) -> None: # noqa:
|
|||
/ f"Frameworks/{apple_multiarch(host)}"
|
||||
)
|
||||
|
||||
run([
|
||||
sys.executable,
|
||||
"Apple/testbed",
|
||||
"clone",
|
||||
"--platform",
|
||||
context.platform,
|
||||
"--framework",
|
||||
framework_path,
|
||||
testbed_dir,
|
||||
])
|
||||
run(
|
||||
[
|
||||
sys.executable,
|
||||
"Apple/testbed",
|
||||
"clone",
|
||||
"--platform",
|
||||
context.platform,
|
||||
"--framework",
|
||||
framework_path,
|
||||
testbed_dir,
|
||||
]
|
||||
)
|
||||
|
||||
run(
|
||||
[
|
||||
|
|
@ -828,7 +823,7 @@ def test(context: argparse.Namespace, host: str | None = None) -> None: # noqa:
|
|||
+ [
|
||||
"--",
|
||||
"test",
|
||||
f"--{context.ci_mode}-ci",
|
||||
"--slow-ci" if context.slow else "--fast-ci",
|
||||
"--single-process",
|
||||
"--no-randomize",
|
||||
# Timeout handling requires subprocesses; explicitly setting
|
||||
|
|
@ -841,39 +836,11 @@ def test(context: argparse.Namespace, host: str | None = None) -> None: # noqa:
|
|||
)
|
||||
|
||||
|
||||
def apple_sim_host(platform_name: str) -> str:
|
||||
"""Determine the native simulator target for this platform."""
|
||||
for _, slice_parts in HOSTS[platform_name].items():
|
||||
for host_triple in slice_parts:
|
||||
parts = host_triple.split("-")
|
||||
if parts[0] == platform.machine() and parts[-1] == "simulator":
|
||||
return host_triple
|
||||
|
||||
raise KeyError(platform_name)
|
||||
|
||||
|
||||
def ci(context: argparse.Namespace) -> None:
|
||||
"""The implementation of the "ci" command.
|
||||
|
||||
In "Fast" mode, this compiles the build python, and the simulator for the
|
||||
build machine's architecture; and runs the test suite with `--fast-ci`
|
||||
configuration.
|
||||
|
||||
In "Slow" mode, it compiles the build python, plus all candidate
|
||||
architectures (both device and simulator); then runs the test suite with
|
||||
`--slow-ci` configuration.
|
||||
"""
|
||||
"""The implementation of the "ci" command."""
|
||||
clean(context, "all")
|
||||
if context.ci_mode == "slow":
|
||||
# In slow mode, build and test the full XCframework
|
||||
build(context, host="all")
|
||||
test(context, host="all")
|
||||
else:
|
||||
# In fast mode, just build the simulator platform.
|
||||
sim_host = apple_sim_host(context.platform)
|
||||
build(context, host="build")
|
||||
build(context, host=sim_host)
|
||||
test(context, host=sim_host)
|
||||
build(context, host="all")
|
||||
test(context, host="all")
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
|
|
@ -973,28 +940,17 @@ def parse_args() -> argparse.Namespace:
|
|||
cmd.add_argument(
|
||||
"--simulator",
|
||||
help=(
|
||||
"The name of the simulator to use (eg: 'iPhone 16e'). "
|
||||
"Defaults to the most recently released 'entry level' "
|
||||
"iPhone device. Device architecture and OS version can also "
|
||||
"be specified; e.g., "
|
||||
"`--simulator 'iPhone 16 Pro,arch=arm64,OS=26.0'` would "
|
||||
"run on an ARM64 iPhone 16 Pro simulator running iOS 26.0."
|
||||
"The name of the simulator to use (eg: 'iPhone 16e'). Defaults to "
|
||||
"the most recently released 'entry level' iPhone device. Device "
|
||||
"architecture and OS version can also be specified; e.g., "
|
||||
"`--simulator 'iPhone 16 Pro,arch=arm64,OS=26.0'` would run on "
|
||||
"an ARM64 iPhone 16 Pro simulator running iOS 26.0."
|
||||
),
|
||||
)
|
||||
group = cmd.add_mutually_exclusive_group()
|
||||
group.add_argument(
|
||||
"--fast-ci",
|
||||
action="store_const",
|
||||
dest="ci_mode",
|
||||
const="fast",
|
||||
help="Add test arguments for GitHub Actions",
|
||||
)
|
||||
group.add_argument(
|
||||
"--slow-ci",
|
||||
action="store_const",
|
||||
dest="ci_mode",
|
||||
const="slow",
|
||||
help="Add test arguments for buildbots",
|
||||
cmd.add_argument(
|
||||
"--slow",
|
||||
action="store_true",
|
||||
help="Run tests with --slow-ci options.",
|
||||
)
|
||||
|
||||
for subcommand in [configure_build, configure_host, build, ci]:
|
||||
|
|
@ -1056,10 +1012,4 @@ def main() -> None:
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Under the buildbot, stdout is not a TTY, but we must still flush after
|
||||
# every line to make sure our output appears in the correct order relative
|
||||
# to the output of our subprocesses.
|
||||
for stream in [sys.stdout, sys.stderr]:
|
||||
stream.reconfigure(line_buffering=True)
|
||||
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -224,17 +224,6 @@ Once you have a built an XCframework, you can test that framework by running:
|
|||
|
||||
$ python Apple test iOS
|
||||
|
||||
This test will attempt to find an "SE-class" simulator (i.e., an iPhone SE, or
|
||||
iPhone 16e, or similar), and run the test suite on the most recent version of
|
||||
iOS that is available. You can specify a simulator using the `--simulator`
|
||||
command line argument, providing the name of the simulator (e.g., `--simulator
|
||||
'iPhone 16 Pro'`). You can also use this argument to control the OS version used
|
||||
for testing; `--simulator 'iPhone 16 Pro,OS=18.2'` would attempt to run the
|
||||
tests on an iPhone 16 Pro running iOS 18.2.
|
||||
|
||||
If the test runner is executed on GitHub Actions, the `GITHUB_ACTIONS`
|
||||
environment variable will be exposed to the iOS process at runtime.
|
||||
|
||||
### Testing a single-architecture framework
|
||||
|
||||
The `Apple/testbed` folder that contains an Xcode project that is able to run
|
||||
|
|
|
|||
|
|
@ -46,8 +46,7 @@ install_stdlib() {
|
|||
rsync -au --delete "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/"
|
||||
rsync -au "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/$SLICE_FOLDER/lib-$ARCHS/" "$CODESIGNING_FOLDER_PATH/python/lib/"
|
||||
else
|
||||
# A single-arch framework will have a libpython symlink; that can't be included at runtime
|
||||
rsync -au --delete "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/$SLICE_FOLDER/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/" --exclude 'libpython*.dylib'
|
||||
rsync -au --delete "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/$SLICE_FOLDER/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/"
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,9 +35,6 @@
|
|||
setenv("NO_COLOR", "1", true);
|
||||
setenv("PYTHON_COLORS", "0", true);
|
||||
|
||||
if (getenv("GITHUB_ACTIONS")) {
|
||||
NSLog(@"Running in a GitHub Actions environment");
|
||||
}
|
||||
// Arguments to pass into the test suite runner.
|
||||
// argv[0] must identify the process; any subsequent arg
|
||||
// will be handled as if it were an argument to `python -m test`
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
|
@ -32,15 +30,15 @@ def select_simulator_device(platform):
|
|||
json_data = json.loads(raw_json)
|
||||
|
||||
if platform == "iOS":
|
||||
# Any iOS device will do; we'll look for "SE" devices - but the name
|
||||
# isn't consistent over time. Older Xcode versions will use "iPhone SE
|
||||
# (Nth generation)"; As of 2025, they've started using "iPhone 16e".
|
||||
# Any iOS device will do; we'll look for "SE" devices - but the name isn't
|
||||
# consistent over time. Older Xcode versions will use "iPhone SE (Nth
|
||||
# generation)"; As of 2025, they've started using "iPhone 16e".
|
||||
#
|
||||
# When Xcode is updated after a new release, new devices will be
|
||||
# available and old ones will be dropped from the set available on the
|
||||
# latest iOS version. Select the one with the highest minimum runtime
|
||||
# version - this is an indicator of the "newest" released device, which
|
||||
# should always be supported on the "most recent" iOS version.
|
||||
# When Xcode is updated after a new release, new devices will be available
|
||||
# and old ones will be dropped from the set available on the latest iOS
|
||||
# version. Select the one with the highest minimum runtime version - this
|
||||
# is an indicator of the "newest" released device, which should always be
|
||||
# supported on the "most recent" iOS version.
|
||||
se_simulators = sorted(
|
||||
(devicetype["minRuntimeVersion"], devicetype["name"])
|
||||
for devicetype in json_data["devicetypes"]
|
||||
|
|
@ -80,13 +78,6 @@ def xcode_test(location: Path, platform: str, simulator: str, verbose: bool):
|
|||
check=True,
|
||||
)
|
||||
|
||||
# Any environment variable prefixed with TEST_RUNNER_ is exposed into the
|
||||
# test runner environment. There are some variables (like those identifying
|
||||
# CI platforms) that can be useful to have access to.
|
||||
test_env = os.environ.copy()
|
||||
if "GITHUB_ACTIONS" in os.environ:
|
||||
test_env["TEST_RUNNER_GITHUB_ACTIONS"] = os.environ["GITHUB_ACTIONS"]
|
||||
|
||||
print("Running test project...")
|
||||
# Test execution *can't* be run -quiet; verbose mode
|
||||
# is how we see the output of the test output.
|
||||
|
|
@ -94,7 +85,6 @@ def xcode_test(location: Path, platform: str, simulator: str, verbose: bool):
|
|||
["xcodebuild", "test-without-building"] + args,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
env=test_env,
|
||||
)
|
||||
while line := (process.stdout.readline()).decode(*DECODE_ARGS):
|
||||
# Strip the timestamp/process prefix from each log line
|
||||
|
|
@ -253,7 +243,7 @@ def update_test_plan(testbed_path, platform, args):
|
|||
test_plan = json.load(f)
|
||||
|
||||
test_plan["defaultOptions"]["commandLineArgumentEntries"] = [
|
||||
{"argument": shlex.quote(arg)} for arg in args
|
||||
{"argument": arg} for arg in args
|
||||
]
|
||||
|
||||
with test_plan_path.open("w", encoding="utf-8") as f:
|
||||
|
|
@ -295,8 +285,7 @@ def main():
|
|||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=(
|
||||
"Manages the process of testing an Apple Python project "
|
||||
"through Xcode."
|
||||
"Manages the process of testing an Apple Python project through Xcode."
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -337,10 +326,7 @@ def main():
|
|||
|
||||
run = subcommands.add_parser(
|
||||
"run",
|
||||
usage=(
|
||||
"%(prog)s [-h] [--simulator SIMULATOR] -- "
|
||||
"<test arg> [<test arg> ...]"
|
||||
),
|
||||
usage="%(prog)s [-h] [--simulator SIMULATOR] -- <test arg> [<test arg> ...]",
|
||||
description=(
|
||||
"Run a testbed project. The arguments provided after `--` will be "
|
||||
"passed to the running iOS process as if they were arguments to "
|
||||
|
|
@ -401,9 +387,9 @@ def main():
|
|||
/ "bin"
|
||||
).is_dir():
|
||||
print(
|
||||
"Testbed does not contain a compiled Python framework. "
|
||||
f"Use `python {sys.argv[0]} clone ...` to create a "
|
||||
"runnable clone of this testbed."
|
||||
f"Testbed does not contain a compiled Python framework. Use "
|
||||
f"`python {sys.argv[0]} clone ...` to create a runnable "
|
||||
f"clone of this testbed."
|
||||
)
|
||||
sys.exit(20)
|
||||
|
||||
|
|
@ -415,8 +401,7 @@ def main():
|
|||
)
|
||||
else:
|
||||
print(
|
||||
"Must specify test arguments "
|
||||
f"(e.g., {sys.argv[0]} run -- test)"
|
||||
f"Must specify test arguments (e.g., {sys.argv[0]} run -- test)"
|
||||
)
|
||||
print()
|
||||
parser.print_help(sys.stderr)
|
||||
|
|
@ -427,9 +412,4 @@ def main():
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Under the buildbot, stdout is not a TTY, but we must still flush after
|
||||
# every line to make sure our output appears in the correct order relative
|
||||
# to the output of our subprocesses.
|
||||
for stream in [sys.stdout, sys.stderr]:
|
||||
stream.reconfigure(line_buffering=True)
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -140,8 +140,7 @@ doctest:
|
|||
pydoc-topics: BUILDER = pydoc-topics
|
||||
pydoc-topics: build
|
||||
@echo "Building finished; now run this:" \
|
||||
"cp build/pydoc-topics/topics.py ../Lib/pydoc_data/topics.py" \
|
||||
"&& cp build/pydoc-topics/module_docs.py ../Lib/pydoc_data/module_docs.py"
|
||||
"cp build/pydoc-topics/topics.py ../Lib/pydoc_data/topics.py"
|
||||
|
||||
.PHONY: gettext
|
||||
gettext: BUILDER = gettext
|
||||
|
|
@ -242,8 +241,7 @@ dist-pdf:
|
|||
# as otherwise the full latexmk process is run twice.
|
||||
# ($$ is needed to escape the $; https://www.gnu.org/software/make/manual/make.html#Basics-of-Variable-References)
|
||||
-sed -i 's/: all-$$(FMT)/:/' build/latex/Makefile
|
||||
if [ -n "$(filter output-sync,$(value .FEATURES))" ]; then OUTPUTSYNC=--output-sync; else OUTPUTSYNC=; fi && \
|
||||
(cd build/latex; $(MAKE) clean && $(MAKE) --jobs=$$((`getconf _NPROCESSORS_ONLN`+1)) $$OUTPUTSYNC LATEXMKOPTS='-quiet' all-pdf && $(MAKE) FMT=pdf zip bz2)
|
||||
(cd build/latex; $(MAKE) clean && $(MAKE) --jobs=$$((`nproc`+1)) --output-sync LATEXMKOPTS='-quiet' all-pdf && $(MAKE) FMT=pdf zip bz2)
|
||||
cp build/latex/docs-pdf.zip dist/python-$(DISTVERSION)-docs-pdf-a4.zip
|
||||
cp build/latex/docs-pdf.tar.bz2 dist/python-$(DISTVERSION)-docs-pdf-a4.tar.bz2
|
||||
@echo "Build finished and archived!"
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -32,9 +32,8 @@ Contributors to the Python documentation
|
|||
----------------------------------------
|
||||
|
||||
Many people have contributed to the Python language, the Python standard
|
||||
library, and the Python documentation. See the `CPython
|
||||
GitHub repository <https://github.com/python/cpython/graphs/contributors>`__
|
||||
for a partial list of contributors.
|
||||
library, and the Python documentation. See :source:`Misc/ACKS` in the Python
|
||||
source distribution for a partial list of contributors.
|
||||
|
||||
It is only with the input and contributions of the Python community
|
||||
that Python has such wonderful documentation -- Thank You!
|
||||
|
|
|
|||
|
|
@ -19,12 +19,6 @@ If you find a bug in this documentation or would like to propose an improvement,
|
|||
please submit a bug report on the :ref:`issue tracker <using-the-tracker>`. If you
|
||||
have a suggestion on how to fix it, include that as well.
|
||||
|
||||
.. only:: translation
|
||||
|
||||
If the bug or suggested improvement concerns the translation of this
|
||||
documentation, submit the report to the
|
||||
`translation’s repository <TRANSLATION_REPO_>`_ instead.
|
||||
|
||||
You can also open a discussion item on our
|
||||
`Documentation Discourse forum <https://discuss.python.org/c/documentation/26>`_.
|
||||
|
||||
|
|
|
|||
|
|
@ -140,6 +140,10 @@ Allocating Objects on the Heap
|
|||
* :c:member:`~PyTypeObject.tp_alloc`
|
||||
|
||||
|
||||
.. c:function:: void PyObject_Del(void *op)
|
||||
|
||||
Same as :c:func:`PyObject_Free`.
|
||||
|
||||
.. c:var:: PyObject _Py_NoneStruct
|
||||
|
||||
Object which is visible in Python as ``None``. This should only be accessed
|
||||
|
|
@ -152,35 +156,3 @@ Allocating Objects on the Heap
|
|||
:ref:`moduleobjects`
|
||||
To allocate and create extension modules.
|
||||
|
||||
|
||||
Deprecated aliases
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
These are :term:`soft deprecated` aliases to existing functions and macros.
|
||||
They exist solely for backwards compatibility.
|
||||
|
||||
|
||||
.. list-table::
|
||||
:widths: auto
|
||||
:header-rows: 1
|
||||
|
||||
* * Deprecated alias
|
||||
* Function
|
||||
* * .. c:macro:: PyObject_NEW(type, typeobj)
|
||||
* :c:macro:`PyObject_New`
|
||||
* * .. c:macro:: PyObject_NEW_VAR(type, typeobj, n)
|
||||
* :c:macro:`PyObject_NewVar`
|
||||
* * .. c:macro:: PyObject_INIT(op, typeobj)
|
||||
* :c:func:`PyObject_Init`
|
||||
* * .. c:macro:: PyObject_INIT_VAR(op, typeobj, n)
|
||||
* :c:func:`PyObject_InitVar`
|
||||
* * .. c:macro:: PyObject_MALLOC(n)
|
||||
* :c:func:`PyObject_Malloc`
|
||||
* * .. c:macro:: PyObject_REALLOC(p, n)
|
||||
* :c:func:`PyObject_Realloc`
|
||||
* * .. c:macro:: PyObject_FREE(p)
|
||||
* :c:func:`PyObject_Free`
|
||||
* * .. c:macro:: PyObject_DEL(p)
|
||||
* :c:func:`PyObject_Free`
|
||||
* * .. c:macro:: PyObject_Del(p)
|
||||
* :c:func:`PyObject_Free`
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ There are three ways strings and buffers can be converted to C:
|
|||
``w*`` (read-write :term:`bytes-like object`) [Py_buffer]
|
||||
This format accepts any object which implements the read-write buffer
|
||||
interface. It fills a :c:type:`Py_buffer` structure provided by the caller.
|
||||
The buffer may contain embedded null bytes. The caller has to call
|
||||
The buffer may contain embedded null bytes. The caller have to call
|
||||
:c:func:`PyBuffer_Release` when it is done with the buffer.
|
||||
|
||||
``es`` (:class:`str`) [const char \*encoding, char \*\*buffer]
|
||||
|
|
|
|||
|
|
@ -261,10 +261,6 @@ readonly, format
|
|||
MUST be consistent for all consumers. For example, :c:expr:`PyBUF_SIMPLE | PyBUF_WRITABLE`
|
||||
can be used to request a simple writable buffer.
|
||||
|
||||
.. c:macro:: PyBUF_WRITEABLE
|
||||
|
||||
This is a :term:`soft deprecated` alias to :c:macro:`PyBUF_WRITABLE`.
|
||||
|
||||
.. c:macro:: PyBUF_FORMAT
|
||||
|
||||
Controls the :c:member:`~Py_buffer.format` field. If set, this field MUST
|
||||
|
|
|
|||
|
|
@ -228,42 +228,6 @@ called with a non-bytes parameter.
|
|||
The function is :term:`soft deprecated`,
|
||||
use the :c:type:`PyBytesWriter` API instead.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyBytes_Repr(PyObject *bytes, int smartquotes)
|
||||
|
||||
Get the string representation of *bytes*. This function is currently used to
|
||||
implement :meth:`!bytes.__repr__` in Python.
|
||||
|
||||
This function does not do type checking; it is undefined behavior to pass
|
||||
*bytes* as a non-bytes object or ``NULL``.
|
||||
|
||||
If *smartquotes* is true, the representation will use a double-quoted string
|
||||
instead of single-quoted string when single-quotes are present in *bytes*.
|
||||
For example, the byte string ``'Python'`` would be represented as
|
||||
``b"'Python'"`` when *smartquotes* is true, or ``b'\'Python\''`` when it is
|
||||
false.
|
||||
|
||||
On success, this function returns a :term:`strong reference` to a
|
||||
:class:`str` object containing the representation. On failure, this
|
||||
returns ``NULL`` with an exception set.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyBytes_DecodeEscape(const char *s, Py_ssize_t len, const char *errors, Py_ssize_t unicode, const char *recode_encoding)
|
||||
|
||||
Unescape a backslash-escaped string *s*. *s* must not be ``NULL``.
|
||||
*len* must be the size of *s*.
|
||||
|
||||
*errors* must be one of ``"strict"``, ``"replace"``, or ``"ignore"``. If
|
||||
*errors* is ``NULL``, then ``"strict"`` is used by default.
|
||||
|
||||
On success, this function returns a :term:`strong reference` to a Python
|
||||
:class:`bytes` object containing the unescaped string. On failure, this
|
||||
function returns ``NULL`` with an exception set.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
*unicode* and *recode_encoding* are now unused.
|
||||
|
||||
|
||||
.. _pybyteswriter:
|
||||
|
||||
PyBytesWriter
|
||||
|
|
@ -295,7 +259,6 @@ Create, Finish, Discard
|
|||
If *size* is greater than zero, allocate *size* bytes, and set the
|
||||
writer size to *size*. The caller is responsible to write *size*
|
||||
bytes using :c:func:`PyBytesWriter_GetData`.
|
||||
This function does not overallocate.
|
||||
|
||||
On error, set an exception and return ``NULL``.
|
||||
|
||||
|
|
@ -386,8 +349,6 @@ Low-level API
|
|||
|
||||
Resize the writer to *size* bytes. It can be used to enlarge or to
|
||||
shrink the writer.
|
||||
This function typically overallocates to achieve amortized performance when
|
||||
resizing multiple times.
|
||||
|
||||
Newly allocated bytes are left uninitialized.
|
||||
|
||||
|
|
@ -399,8 +360,6 @@ Low-level API
|
|||
.. c:function:: int PyBytesWriter_Grow(PyBytesWriter *writer, Py_ssize_t grow)
|
||||
|
||||
Resize the writer by adding *grow* bytes to the current writer size.
|
||||
This function typically overallocates to achieve amortized performance when
|
||||
resizing multiple times.
|
||||
|
||||
Newly allocated bytes are left uninitialized.
|
||||
|
||||
|
|
|
|||
|
|
@ -15,19 +15,13 @@ Refer to :ref:`using-capsules` for more information on using these objects.
|
|||
.. c:type:: PyCapsule
|
||||
|
||||
This subtype of :c:type:`PyObject` represents an opaque value, useful for C
|
||||
extension modules which need to pass an opaque value (as a :c:expr:`void*`
|
||||
extension modules who need to pass an opaque value (as a :c:expr:`void*`
|
||||
pointer) through Python code to other C code. It is often used to make a C
|
||||
function pointer defined in one module available to other modules, so the
|
||||
regular import mechanism can be used to access C APIs defined in dynamically
|
||||
loaded modules.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyCapsule_Type
|
||||
|
||||
The type object corresponding to capsule objects. This is the same object
|
||||
as :class:`types.CapsuleType` in the Python layer.
|
||||
|
||||
|
||||
.. c:type:: PyCapsule_Destructor
|
||||
|
||||
The type of a destructor callback for a capsule. Defined as::
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ Cell Objects
|
|||
|
||||
"Cell" objects are used to implement variables referenced by multiple scopes.
|
||||
For each such variable, a cell object is created to store the value; the local
|
||||
variables of each stack frame that references the value contain a reference to
|
||||
variables of each stack frame that references the value contains a reference to
|
||||
the cells from outer scopes which also use that variable. When the value is
|
||||
accessed, the value contained in the cell is used instead of the cell object
|
||||
itself. This de-referencing of the cell object requires support from the
|
||||
|
|
|
|||
|
|
@ -211,17 +211,6 @@ bound into a function.
|
|||
.. versionadded:: 3.12
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyCode_Optimize(PyObject *code, PyObject *consts, PyObject *names, PyObject *lnotab_obj)
|
||||
|
||||
This is a :term:`soft deprecated` function that does nothing.
|
||||
|
||||
Prior to Python 3.10, this function would perform basic optimizations to a
|
||||
code object.
|
||||
|
||||
.. versionchanged:: 3.10
|
||||
This function now does nothing.
|
||||
|
||||
|
||||
.. _c_codeobject_flags:
|
||||
|
||||
Code Object Flags
|
||||
|
|
@ -300,7 +289,7 @@ may change without deprecation warnings.
|
|||
|
||||
.. c:function:: Py_ssize_t PyUnstable_Eval_RequestCodeExtraIndex(freefunc free)
|
||||
|
||||
Return a new opaque index value used to adding data to code objects.
|
||||
Return a new an opaque index value used to adding data to code objects.
|
||||
|
||||
You generally call this function once (per interpreter) and use the result
|
||||
with ``PyCode_GetExtra`` and ``PyCode_SetExtra`` to manipulate
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ Codec registry and support functions
|
|||
|
||||
Register a new codec search function.
|
||||
|
||||
As a side effect, this tries to load the :mod:`!encodings` package, if not yet
|
||||
As side effect, this tries to load the :mod:`!encodings` package, if not yet
|
||||
done, to make sure that it is always first in the list of search functions.
|
||||
|
||||
.. c:function:: int PyCodec_Unregister(PyObject *search_function)
|
||||
|
|
@ -39,7 +39,7 @@ Codec registry and support functions
|
|||
*object* is passed through the decoder function found for the given
|
||||
*encoding* using the error handling method defined by *errors*. *errors* may
|
||||
be ``NULL`` to use the default method defined for the codec. Raises a
|
||||
:exc:`LookupError` if no decoder can be found.
|
||||
:exc:`LookupError` if no encoder can be found.
|
||||
|
||||
|
||||
Codec lookup API
|
||||
|
|
@ -129,13 +129,3 @@ Registry API for Unicode encoding error handlers
|
|||
Replace the unicode encode error with ``\N{...}`` escapes.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
|
||||
Codec utility variables
|
||||
-----------------------
|
||||
|
||||
.. c:var:: const char *Py_hexdigits
|
||||
|
||||
A string constant containing the lowercase hexadecimal digits: ``"0123456789abcdef"``.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ Complex Number Objects
|
|||
|
||||
.. c:type:: Py_complex
|
||||
|
||||
This C structure defines an export format for a Python complex
|
||||
This C structure defines export format for a Python complex
|
||||
number object.
|
||||
|
||||
.. c:member:: double real
|
||||
|
|
|
|||
|
|
@ -109,20 +109,11 @@ Other Objects
|
|||
descriptor.rst
|
||||
slice.rst
|
||||
memoryview.rst
|
||||
picklebuffer.rst
|
||||
weakref.rst
|
||||
capsule.rst
|
||||
frame.rst
|
||||
gen.rst
|
||||
coro.rst
|
||||
contextvars.rst
|
||||
typehints.rst
|
||||
|
||||
|
||||
C API for extension modules
|
||||
===========================
|
||||
|
||||
.. toctree::
|
||||
|
||||
curses.rst
|
||||
datetime.rst
|
||||
typehints.rst
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ The return value (*rv*) for these functions should be interpreted as follows:
|
|||
``rv + 1`` bytes would have been needed to succeed. ``str[size-1]`` is ``'\0'``
|
||||
in this case.
|
||||
|
||||
* When ``rv < 0``, the output conversion failed and ``str[size-1]`` is ``'\0'`` in
|
||||
* When ``rv < 0``, "something bad happened." ``str[size-1]`` is ``'\0'`` in
|
||||
this case too, but the rest of *str* is undefined. The exact cause of the error
|
||||
depends on the underlying platform.
|
||||
|
||||
|
|
@ -105,7 +105,7 @@ The following functions provide locale-independent string to number conversions.
|
|||
|
||||
If ``s`` represents a value that is too large to store in a float
|
||||
(for example, ``"1e500"`` is such a string on many platforms) then
|
||||
if ``overflow_exception`` is ``NULL`` return :c:macro:`!INFINITY` (with
|
||||
if ``overflow_exception`` is ``NULL`` return ``Py_INFINITY`` (with
|
||||
an appropriate sign) and don't set any exception. Otherwise,
|
||||
``overflow_exception`` must point to a Python exception object;
|
||||
raise that exception and return ``-1.0``. In both cases, set
|
||||
|
|
@ -128,28 +128,18 @@ The following functions provide locale-independent string to number conversions.
|
|||
must be 0 and is ignored. The ``'r'`` format code specifies the
|
||||
standard :func:`repr` format.
|
||||
|
||||
*flags* can be zero or more of the following values or-ed together:
|
||||
*flags* can be zero or more of the values ``Py_DTSF_SIGN``,
|
||||
``Py_DTSF_ADD_DOT_0``, or ``Py_DTSF_ALT``, or-ed together:
|
||||
|
||||
.. c:macro:: Py_DTSF_SIGN
|
||||
* ``Py_DTSF_SIGN`` means to always precede the returned string with a sign
|
||||
character, even if *val* is non-negative.
|
||||
|
||||
Always precede the returned string with a sign
|
||||
character, even if *val* is non-negative.
|
||||
* ``Py_DTSF_ADD_DOT_0`` means to ensure that the returned string will not look
|
||||
like an integer.
|
||||
|
||||
.. c:macro:: Py_DTSF_ADD_DOT_0
|
||||
|
||||
Ensure that the returned string will not look like an integer.
|
||||
|
||||
.. c:macro:: Py_DTSF_ALT
|
||||
|
||||
Apply "alternate" formatting rules.
|
||||
See the documentation for the :c:func:`PyOS_snprintf` ``'#'`` specifier for
|
||||
details.
|
||||
|
||||
.. c:macro:: Py_DTSF_NO_NEG_0
|
||||
|
||||
Negative zero is converted to positive zero.
|
||||
|
||||
.. versionadded:: 3.11
|
||||
* ``Py_DTSF_ALT`` means to apply "alternate" formatting rules. See the
|
||||
documentation for the :c:func:`PyOS_snprintf` ``'#'`` specifier for
|
||||
details.
|
||||
|
||||
If *ptype* is non-``NULL``, then the value it points to will be set to one of
|
||||
``Py_DTST_FINITE``, ``Py_DTST_INFINITE``, or ``Py_DTST_NAN``, signifying that
|
||||
|
|
@ -162,85 +152,13 @@ The following functions provide locale-independent string to number conversions.
|
|||
.. versionadded:: 3.1
|
||||
|
||||
|
||||
.. c:function:: int PyOS_mystricmp(const char *str1, const char *str2)
|
||||
int PyOS_mystrnicmp(const char *str1, const char *str2, Py_ssize_t size)
|
||||
.. c:function:: int PyOS_stricmp(const char *s1, const char *s2)
|
||||
|
||||
Case insensitive comparison of strings. These functions work almost
|
||||
identically to :c:func:`!strcmp` and :c:func:`!strncmp` (respectively),
|
||||
except that they ignore the case of ASCII characters.
|
||||
|
||||
Return ``0`` if the strings are equal, a negative value if *str1* sorts
|
||||
lexicographically before *str2*, or a positive value if it sorts after.
|
||||
|
||||
In the *str1* or *str2* arguments, a NUL byte marks the end of the string.
|
||||
For :c:func:`!PyOS_mystrnicmp`, the *size* argument gives the maximum size
|
||||
of the string, as if NUL was present at the index given by *size*.
|
||||
|
||||
These functions do not use the locale.
|
||||
Case insensitive comparison of strings. The function works almost
|
||||
identically to :c:func:`!strcmp` except that it ignores the case.
|
||||
|
||||
|
||||
.. c:function:: int PyOS_stricmp(const char *str1, const char *str2)
|
||||
int PyOS_strnicmp(const char *str1, const char *str2, Py_ssize_t size)
|
||||
.. c:function:: int PyOS_strnicmp(const char *s1, const char *s2, Py_ssize_t size)
|
||||
|
||||
Case insensitive comparison of strings.
|
||||
|
||||
On Windows, these are aliases of :c:func:`!stricmp` and :c:func:`!strnicmp`,
|
||||
respectively.
|
||||
|
||||
On other platforms, they are aliases of :c:func:`PyOS_mystricmp` and
|
||||
:c:func:`PyOS_mystrnicmp`, respectively.
|
||||
|
||||
|
||||
Character classification and conversion
|
||||
=======================================
|
||||
|
||||
The following macros provide locale-independent (unlike the C standard library
|
||||
``ctype.h``) character classification and conversion.
|
||||
The argument must be a signed or unsigned :c:expr:`char`.
|
||||
|
||||
|
||||
.. c:macro:: Py_ISALNUM(c)
|
||||
|
||||
Return true if the character *c* is an alphanumeric character.
|
||||
|
||||
|
||||
.. c:macro:: Py_ISALPHA(c)
|
||||
|
||||
Return true if the character *c* is an alphabetic character (``a-z`` and ``A-Z``).
|
||||
|
||||
|
||||
.. c:macro:: Py_ISDIGIT(c)
|
||||
|
||||
Return true if the character *c* is a decimal digit (``0-9``).
|
||||
|
||||
|
||||
.. c:macro:: Py_ISLOWER(c)
|
||||
|
||||
Return true if the character *c* is a lowercase ASCII letter (``a-z``).
|
||||
|
||||
|
||||
.. c:macro:: Py_ISUPPER(c)
|
||||
|
||||
Return true if the character *c* is an uppercase ASCII letter (``A-Z``).
|
||||
|
||||
|
||||
.. c:macro:: Py_ISSPACE(c)
|
||||
|
||||
Return true if the character *c* is a whitespace character (space, tab,
|
||||
carriage return, newline, vertical tab, or form feed).
|
||||
|
||||
|
||||
.. c:macro:: Py_ISXDIGIT(c)
|
||||
|
||||
Return true if the character *c* is a hexadecimal digit (``0-9``, ``a-f``, and
|
||||
``A-F``).
|
||||
|
||||
|
||||
.. c:macro:: Py_TOLOWER(c)
|
||||
|
||||
Return the lowercase equivalent of the character *c*.
|
||||
|
||||
|
||||
.. c:macro:: Py_TOUPPER(c)
|
||||
|
||||
Return the uppercase equivalent of the character *c*.
|
||||
Case insensitive comparison of strings. The function works almost
|
||||
identically to :c:func:`!strncmp` except that it ignores the case.
|
||||
|
|
|
|||
|
|
@ -1,138 +0,0 @@
|
|||
.. highlight:: c
|
||||
|
||||
Curses C API
|
||||
------------
|
||||
|
||||
:mod:`curses` exposes a small C interface for extension modules.
|
||||
Consumers must include the header file :file:`py_curses.h` (which is not
|
||||
included by default by :file:`Python.h`) and :c:func:`import_curses` must
|
||||
be invoked, usually as part of the module initialisation function, to populate
|
||||
:c:var:`PyCurses_API`.
|
||||
|
||||
.. warning::
|
||||
|
||||
Neither the C API nor the pure Python :mod:`curses` module are compatible
|
||||
with subinterpreters.
|
||||
|
||||
.. c:macro:: import_curses()
|
||||
|
||||
Import the curses C API. The macro does not need a semi-colon to be called.
|
||||
|
||||
On success, populate the :c:var:`PyCurses_API` pointer.
|
||||
|
||||
On failure, set :c:var:`PyCurses_API` to NULL and set an exception.
|
||||
The caller must check if an error occurred via :c:func:`PyErr_Occurred`:
|
||||
|
||||
.. code-block::
|
||||
|
||||
import_curses(); // semi-colon is optional but recommended
|
||||
if (PyErr_Occurred()) { /* cleanup */ }
|
||||
|
||||
|
||||
.. c:var:: void **PyCurses_API
|
||||
|
||||
Dynamically allocated object containing the curses C API.
|
||||
This variable is only available once :c:macro:`import_curses` succeeds.
|
||||
|
||||
``PyCurses_API[0]`` corresponds to :c:data:`PyCursesWindow_Type`.
|
||||
|
||||
``PyCurses_API[1]``, ``PyCurses_API[2]``, and ``PyCurses_API[3]``
|
||||
are pointers to predicate functions of type ``int (*)(void)``.
|
||||
|
||||
When called, these predicates return whether :func:`curses.setupterm`,
|
||||
:func:`curses.initscr`, and :func:`curses.start_color` have been called
|
||||
respectively.
|
||||
|
||||
See also the convenience macros :c:macro:`PyCursesSetupTermCalled`,
|
||||
:c:macro:`PyCursesInitialised`, and :c:macro:`PyCursesInitialisedColor`.
|
||||
|
||||
.. note::
|
||||
|
||||
The number of entries in this structure is subject to changes.
|
||||
Consider using :c:macro:`PyCurses_API_pointers` to check if
|
||||
new fields are available or not.
|
||||
|
||||
|
||||
.. c:macro:: PyCurses_API_pointers
|
||||
|
||||
The number of accessible fields (``4``) in :c:var:`PyCurses_API`.
|
||||
This number is incremented whenever new fields are added.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyCursesWindow_Type
|
||||
|
||||
The :ref:`heap type <heap-types>` corresponding to :class:`curses.window`.
|
||||
|
||||
|
||||
.. c:function:: int PyCursesWindow_Check(PyObject *op)
|
||||
|
||||
Return true if *op* is a :class:`curses.window` instance, false otherwise.
|
||||
|
||||
|
||||
The following macros are convenience macros expanding into C statements.
|
||||
In particular, they can only be used as ``macro;`` or ``macro``, but not
|
||||
``macro()`` or ``macro();``.
|
||||
|
||||
.. c:macro:: PyCursesSetupTermCalled
|
||||
|
||||
Macro checking if :func:`curses.setupterm` has been called.
|
||||
|
||||
The macro expansion is roughly equivalent to:
|
||||
|
||||
.. code-block::
|
||||
|
||||
{
|
||||
typedef int (*predicate_t)(void);
|
||||
predicate_t was_setupterm_called = (predicate_t)PyCurses_API[1];
|
||||
if (!was_setupterm_called()) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.. c:macro:: PyCursesInitialised
|
||||
|
||||
Macro checking if :func:`curses.initscr` has been called.
|
||||
|
||||
The macro expansion is roughly equivalent to:
|
||||
|
||||
.. code-block::
|
||||
|
||||
{
|
||||
typedef int (*predicate_t)(void);
|
||||
predicate_t was_initscr_called = (predicate_t)PyCurses_API[2];
|
||||
if (!was_initscr_called()) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.. c:macro:: PyCursesInitialisedColor
|
||||
|
||||
Macro checking if :func:`curses.start_color` has been called.
|
||||
|
||||
The macro expansion is roughly equivalent to:
|
||||
|
||||
.. code-block::
|
||||
|
||||
{
|
||||
typedef int (*predicate_t)(void);
|
||||
predicate_t was_start_color_called = (predicate_t)PyCurses_API[3];
|
||||
if (!was_start_color_called()) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Internal data
|
||||
-------------
|
||||
|
||||
The following objects are exposed by the C API but should be considered
|
||||
internal-only.
|
||||
|
||||
.. c:macro:: PyCurses_CAPSULE_NAME
|
||||
|
||||
Name of the curses capsule to pass to :c:func:`PyCapsule_Import`.
|
||||
|
||||
Internal usage only. Use :c:macro:`import_curses` instead.
|
||||
|
||||
|
|
@ -8,42 +8,11 @@ DateTime Objects
|
|||
Various date and time objects are supplied by the :mod:`datetime` module.
|
||||
Before using any of these functions, the header file :file:`datetime.h` must be
|
||||
included in your source (note that this is not included by :file:`Python.h`),
|
||||
and the macro :c:macro:`PyDateTime_IMPORT` must be invoked, usually as part of
|
||||
and the macro :c:macro:`!PyDateTime_IMPORT` must be invoked, usually as part of
|
||||
the module initialisation function. The macro puts a pointer to a C structure
|
||||
into a static variable, :c:data:`PyDateTimeAPI`, that is used by the following
|
||||
into a static variable, :c:data:`!PyDateTimeAPI`, that is used by the following
|
||||
macros.
|
||||
|
||||
.. c:macro:: PyDateTime_IMPORT()
|
||||
|
||||
Import the datetime C API.
|
||||
|
||||
On success, populate the :c:var:`PyDateTimeAPI` pointer.
|
||||
On failure, set :c:var:`PyDateTimeAPI` to ``NULL`` and set an exception.
|
||||
The caller must check if an error occurred via :c:func:`PyErr_Occurred`:
|
||||
|
||||
.. code-block::
|
||||
|
||||
PyDateTime_IMPORT;
|
||||
if (PyErr_Occurred()) { /* cleanup */ }
|
||||
|
||||
.. warning::
|
||||
|
||||
This is not compatible with subinterpreters.
|
||||
|
||||
.. c:type:: PyDateTime_CAPI
|
||||
|
||||
Structure containing the fields for the datetime C API.
|
||||
|
||||
The fields of this structure are private and subject to change.
|
||||
|
||||
Do not use this directly; prefer ``PyDateTime_*`` APIs instead.
|
||||
|
||||
.. c:var:: PyDateTime_CAPI *PyDateTimeAPI
|
||||
|
||||
Dynamically allocated object containing the datetime C API.
|
||||
|
||||
This variable is only available once :c:macro:`PyDateTime_IMPORT` succeeds.
|
||||
|
||||
.. c:type:: PyDateTime_Date
|
||||
|
||||
This subtype of :c:type:`PyObject` represents a Python date object.
|
||||
|
|
@ -77,7 +46,7 @@ macros.
|
|||
|
||||
.. c:var:: PyTypeObject PyDateTime_DeltaType
|
||||
|
||||
This instance of :c:type:`PyTypeObject` represents the Python type for
|
||||
This instance of :c:type:`PyTypeObject` represents Python type for
|
||||
the difference between two datetime values;
|
||||
it is the same object as :class:`datetime.timedelta` in the Python layer.
|
||||
|
||||
|
|
@ -356,16 +325,3 @@ Macros for the convenience of modules implementing the DB API:
|
|||
|
||||
Create and return a new :class:`datetime.date` object given an argument
|
||||
tuple suitable for passing to :meth:`datetime.date.fromtimestamp`.
|
||||
|
||||
|
||||
Internal data
|
||||
-------------
|
||||
|
||||
The following symbols are exposed by the C API but should be considered
|
||||
internal-only.
|
||||
|
||||
.. c:macro:: PyDateTime_CAPSULE_NAME
|
||||
|
||||
Name of the datetime capsule to pass to :c:func:`PyCapsule_Import`.
|
||||
|
||||
Internal usage only. Use :c:macro:`PyDateTime_IMPORT` instead.
|
||||
|
|
|
|||
|
|
@ -21,104 +21,20 @@ found in the dictionary of type objects.
|
|||
.. c:function:: PyObject* PyDescr_NewMember(PyTypeObject *type, struct PyMemberDef *meth)
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyMemberDescr_Type
|
||||
|
||||
The type object for member descriptor objects created from
|
||||
:c:type:`PyMemberDef` structures. These descriptors expose fields of a
|
||||
C struct as attributes on a type, and correspond
|
||||
to :class:`types.MemberDescriptorType` objects in Python.
|
||||
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyGetSetDescr_Type
|
||||
|
||||
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.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDescr_NewMethod(PyTypeObject *type, struct PyMethodDef *meth)
|
||||
|
||||
|
||||
.. 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`
|
||||
objects in Python.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *wrapper, void *wrapped)
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyWrapperDescr_Type
|
||||
|
||||
The type object for wrapper descriptor objects created by
|
||||
:c:func:`PyDescr_NewWrapper` and :c:func:`PyWrapper_New`. Wrapper
|
||||
descriptors are used internally to expose special methods implemented
|
||||
via wrapper structures, and appear in Python as
|
||||
:class:`types.WrapperDescriptorType` objects.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)
|
||||
|
||||
|
||||
.. c:function:: int PyDescr_IsData(PyObject *descr)
|
||||
|
||||
Return non-zero if the descriptor object *descr* describes a data attribute, or
|
||||
Return non-zero if the descriptor objects *descr* describes a data attribute, or
|
||||
``0`` if it describes a method. *descr* must be a descriptor object; there is
|
||||
no error checking.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyWrapper_New(PyObject *, PyObject *)
|
||||
|
||||
|
||||
Built-in descriptors
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. c:var:: PyTypeObject PySuper_Type
|
||||
|
||||
The type object for super objects. This is the same object as
|
||||
:class:`super` in the Python layer.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyClassMethod_Type
|
||||
|
||||
The type of class method objects. This is the same object as
|
||||
:class:`classmethod` in the Python layer.
|
||||
|
||||
|
||||
.. 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.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyClassMethod_New(PyObject *callable)
|
||||
|
||||
Create a new :class:`classmethod` object wrapping *callable*.
|
||||
*callable* must be a callable object and must not be ``NULL``.
|
||||
|
||||
On success, this function returns a :term:`strong reference` to a new class
|
||||
method descriptor. On failure, this function returns ``NULL`` with an
|
||||
exception set.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyStaticMethod_Type
|
||||
|
||||
The type of static method objects. This is the same object as
|
||||
:class:`staticmethod` in the Python layer.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyStaticMethod_New(PyObject *callable)
|
||||
|
||||
Create a new :class:`staticmethod` object wrapping *callable*.
|
||||
*callable* must be a callable object and must not be ``NULL``.
|
||||
|
||||
On success, this function returns a :term:`strong reference` to a new static
|
||||
method descriptor. On failure, this function returns ``NULL`` with an
|
||||
exception set.
|
||||
|
||||
|
|
|
|||
|
|
@ -43,17 +43,6 @@ Dictionary Objects
|
|||
prevent modification of the dictionary for non-dynamic class types.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyDictProxy_Type
|
||||
|
||||
The type object for mapping proxy objects created by
|
||||
:c:func:`PyDictProxy_New` and for the read-only ``__dict__`` attribute
|
||||
of many built-in types. A :c:type:`PyDictProxy_Type` instance provides a
|
||||
dynamic, read-only view of an underlying dictionary: changes to the
|
||||
underlying dictionary are reflected in the proxy, but the proxy itself
|
||||
does not support mutation operations. This corresponds to
|
||||
:class:`types.MappingProxyType` in Python.
|
||||
|
||||
|
||||
.. c:function:: void PyDict_Clear(PyObject *p)
|
||||
|
||||
Empty an existing dictionary of all key-value pairs.
|
||||
|
|
@ -61,7 +50,7 @@ Dictionary Objects
|
|||
|
||||
.. c:function:: int PyDict_Contains(PyObject *p, PyObject *key)
|
||||
|
||||
Determine if dictionary *p* contains *key*. If an item in *p* matches
|
||||
Determine if dictionary *p* contains *key*. If an item in *p* is matches
|
||||
*key*, return ``1``, otherwise return ``0``. On error, return ``-1``.
|
||||
This is equivalent to the Python expression ``key in p``.
|
||||
|
||||
|
|
@ -209,7 +198,7 @@ Dictionary Objects
|
|||
.. c:function:: int PyDict_Pop(PyObject *p, PyObject *key, PyObject **result)
|
||||
|
||||
Remove *key* from dictionary *p* and optionally return the removed value.
|
||||
Do not raise :exc:`KeyError` if the key is missing.
|
||||
Do not raise :exc:`KeyError` if the key missing.
|
||||
|
||||
- If the key is present, set *\*result* to a new reference to the removed
|
||||
value if *result* is not ``NULL``, and return ``1``.
|
||||
|
|
@ -218,7 +207,7 @@ Dictionary Objects
|
|||
- On error, raise an exception and return ``-1``.
|
||||
|
||||
Similar to :meth:`dict.pop`, but without the default value and
|
||||
not raising :exc:`KeyError` if the key is missing.
|
||||
not raising :exc:`KeyError` if the key missing.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
|
@ -256,11 +245,6 @@ Dictionary Objects
|
|||
``len(p)`` on a dictionary.
|
||||
|
||||
|
||||
.. c:function:: Py_ssize_t PyDict_GET_SIZE(PyObject *p)
|
||||
|
||||
Similar to :c:func:`PyDict_Size`, but without error checking.
|
||||
|
||||
|
||||
.. c:function:: int PyDict_Next(PyObject *p, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue)
|
||||
|
||||
Iterate over all key-value pairs in the dictionary *p*. The
|
||||
|
|
@ -442,138 +426,3 @@ Dictionary Objects
|
|||
it before returning.
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
|
||||
Dictionary View Objects
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. c:function:: int PyDictViewSet_Check(PyObject *op)
|
||||
|
||||
Return true if *op* is a view of a set inside a dictionary. This is currently
|
||||
equivalent to :c:expr:`PyDictKeys_Check(op) || PyDictItems_Check(op)`. This
|
||||
function always succeeds.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyDictKeys_Type
|
||||
|
||||
Type object for a view of dictionary keys. In Python, this is the type of
|
||||
the object returned by :meth:`dict.keys`.
|
||||
|
||||
|
||||
.. c:function:: int PyDictKeys_Check(PyObject *op)
|
||||
|
||||
Return true if *op* is an instance of a dictionary keys view. This function
|
||||
always succeeds.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyDictValues_Type
|
||||
|
||||
Type object for a view of dictionary values. In Python, this is the type of
|
||||
the object returned by :meth:`dict.values`.
|
||||
|
||||
|
||||
.. c:function:: int PyDictValues_Check(PyObject *op)
|
||||
|
||||
Return true if *op* is an instance of a dictionary values view. This function
|
||||
always succeeds.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyDictItems_Type
|
||||
|
||||
Type object for a view of dictionary items. In Python, this is the type of
|
||||
the object returned by :meth:`dict.items`.
|
||||
|
||||
|
||||
.. c:function:: int PyDictItems_Check(PyObject *op)
|
||||
|
||||
Return true if *op* is an instance of a dictionary items view. This function
|
||||
always succeeds.
|
||||
|
||||
|
||||
Ordered Dictionaries
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Python's C API provides interface for :class:`collections.OrderedDict` from C.
|
||||
Since Python 3.7, dictionaries are ordered by default, so there is usually
|
||||
little need for these functions; prefer ``PyDict*`` where possible.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyODict_Type
|
||||
|
||||
Type object for ordered dictionaries. This is the same object as
|
||||
:class:`collections.OrderedDict` in the Python layer.
|
||||
|
||||
|
||||
.. c:function:: int PyODict_Check(PyObject *od)
|
||||
|
||||
Return true if *od* is an ordered dictionary object or an instance of a
|
||||
subtype of the :class:`~collections.OrderedDict` type. This function
|
||||
always succeeds.
|
||||
|
||||
|
||||
.. c:function:: int PyODict_CheckExact(PyObject *od)
|
||||
|
||||
Return true if *od* is an ordered dictionary object, but not an instance of
|
||||
a subtype of the :class:`~collections.OrderedDict` type.
|
||||
This function always succeeds.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyODictKeys_Type
|
||||
|
||||
Analogous to :c:type:`PyDictKeys_Type` for ordered dictionaries.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyODictValues_Type
|
||||
|
||||
Analogous to :c:type:`PyDictValues_Type` for ordered dictionaries.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyODictItems_Type
|
||||
|
||||
Analogous to :c:type:`PyDictItems_Type` for ordered dictionaries.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyODict_New(void)
|
||||
|
||||
Return a new empty ordered dictionary, or ``NULL`` on failure.
|
||||
|
||||
This is analogous to :c:func:`PyDict_New`.
|
||||
|
||||
|
||||
.. c:function:: int PyODict_SetItem(PyObject *od, PyObject *key, PyObject *value)
|
||||
|
||||
Insert *value* into the ordered dictionary *od* with a key of *key*.
|
||||
Return ``0`` on success or ``-1`` with an exception set on failure.
|
||||
|
||||
This is analogous to :c:func:`PyDict_SetItem`.
|
||||
|
||||
|
||||
.. c:function:: int PyODict_DelItem(PyObject *od, PyObject *key)
|
||||
|
||||
Remove the entry in the ordered dictionary *od* with key *key*.
|
||||
Return ``0`` on success or ``-1`` with an exception set on failure.
|
||||
|
||||
This is analogous to :c:func:`PyDict_DelItem`.
|
||||
|
||||
|
||||
These are :term:`soft deprecated` aliases to ``PyDict`` APIs:
|
||||
|
||||
|
||||
.. list-table::
|
||||
:widths: auto
|
||||
:header-rows: 1
|
||||
|
||||
* * ``PyODict``
|
||||
* ``PyDict``
|
||||
* * .. c:macro:: PyODict_GetItem(od, key)
|
||||
* :c:func:`PyDict_GetItem`
|
||||
* * .. c:macro:: PyODict_GetItemWithError(od, key)
|
||||
* :c:func:`PyDict_GetItemWithError`
|
||||
* * .. c:macro:: PyODict_GetItemString(od, key)
|
||||
* :c:func:`PyDict_GetItemString`
|
||||
* * .. c:macro:: PyODict_Contains(od, key)
|
||||
* :c:func:`PyDict_Contains`
|
||||
* * .. c:macro:: PyODict_Size(od)
|
||||
* :c:func:`PyDict_Size`
|
||||
* * .. c:macro:: PyODict_SIZE(od)
|
||||
* :c:func:`PyDict_GET_SIZE`
|
||||
|
|
|
|||
|
|
@ -309,14 +309,6 @@ For convenience, some of these functions will always return a
|
|||
.. versionadded:: 3.4
|
||||
|
||||
|
||||
.. c:function:: void PyErr_RangedSyntaxLocationObject(PyObject *filename, int lineno, int col_offset, int end_lineno, int end_col_offset)
|
||||
|
||||
Similar to :c:func:`PyErr_SyntaxLocationObject`, but also sets the
|
||||
*end_lineno* and *end_col_offset* information for the current exception.
|
||||
|
||||
.. versionadded:: 3.10
|
||||
|
||||
|
||||
.. c:function:: void PyErr_SyntaxLocationEx(const char *filename, int lineno, int col_offset)
|
||||
|
||||
Like :c:func:`PyErr_SyntaxLocationObject`, but *filename* is a byte string
|
||||
|
|
@ -339,23 +331,6 @@ For convenience, some of these functions will always return a
|
|||
use.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyErr_ProgramTextObject(PyObject *filename, int lineno)
|
||||
|
||||
Get the source line in *filename* at line *lineno*. *filename* should be a
|
||||
Python :class:`str` object.
|
||||
|
||||
On success, this function returns a Python string object with the found line.
|
||||
On failure, this function returns ``NULL`` without an exception set.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyErr_ProgramText(const char *filename, int lineno)
|
||||
|
||||
Similar to :c:func:`PyErr_ProgramTextObject`, but *filename* is a
|
||||
:c:expr:`const char *`, which is decoded with the
|
||||
:term:`filesystem encoding and error handler`, instead of a
|
||||
Python object reference.
|
||||
|
||||
|
||||
Issuing warnings
|
||||
================
|
||||
|
||||
|
|
@ -419,15 +394,6 @@ an error value).
|
|||
.. versionadded:: 3.2
|
||||
|
||||
|
||||
.. c:function:: int PyErr_WarnExplicitFormat(PyObject *category, const char *filename, int lineno, const char *module, PyObject *registry, const char *format, ...)
|
||||
|
||||
Similar to :c:func:`PyErr_WarnExplicit`, but uses
|
||||
:c:func:`PyUnicode_FromFormat` to format the warning message. *format* is
|
||||
an ASCII-encoded string.
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
|
||||
.. c:function:: int PyErr_ResourceWarning(PyObject *source, Py_ssize_t stack_level, const char *format, ...)
|
||||
|
||||
Function similar to :c:func:`PyErr_WarnFormat`, but *category* is
|
||||
|
|
@ -796,17 +762,6 @@ Exception Classes
|
|||
Exception Objects
|
||||
=================
|
||||
|
||||
.. c:function:: int PyExceptionInstance_Check(PyObject *op)
|
||||
|
||||
Return true if *op* is an instance of :class:`BaseException`, false
|
||||
otherwise. This function always succeeds.
|
||||
|
||||
|
||||
.. c:macro:: PyExceptionInstance_Class(op)
|
||||
|
||||
Equivalent to :c:func:`Py_TYPE(op) <Py_TYPE>`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyException_GetTraceback(PyObject *ex)
|
||||
|
||||
Return the traceback associated with the exception as a new reference, as
|
||||
|
|
@ -984,9 +939,6 @@ because the :ref:`call protocol <call>` takes care of recursion handling.
|
|||
be concatenated to the :exc:`RecursionError` message caused by the recursion
|
||||
depth limit.
|
||||
|
||||
.. seealso::
|
||||
The :c:func:`PyUnstable_ThreadState_SetStackProtection` function.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
This function is now also available in the :ref:`limited API <limited-c-api>`.
|
||||
|
||||
|
|
@ -1027,27 +979,6 @@ these are the C equivalent to :func:`reprlib.recursive_repr`.
|
|||
Ends a :c:func:`Py_ReprEnter`. Must be called once for each
|
||||
invocation of :c:func:`Py_ReprEnter` that returns zero.
|
||||
|
||||
.. c:function:: int Py_GetRecursionLimit(void)
|
||||
|
||||
Get the recursion limit for the current interpreter. It can be set with
|
||||
:c:func:`Py_SetRecursionLimit`. The recursion limit prevents the
|
||||
Python interpreter stack from growing infinitely.
|
||||
|
||||
This function cannot fail, and the caller must hold an
|
||||
:term:`attached thread state`.
|
||||
|
||||
.. seealso::
|
||||
:py:func:`sys.getrecursionlimit`
|
||||
|
||||
.. c:function:: void Py_SetRecursionLimit(int new_limit)
|
||||
|
||||
Set the recursion limit for the current interpreter.
|
||||
|
||||
This function cannot fail, and the caller must hold an
|
||||
:term:`attached thread state`.
|
||||
|
||||
.. seealso::
|
||||
:py:func:`sys.setrecursionlimit`
|
||||
|
||||
.. _standardexceptions:
|
||||
|
||||
|
|
@ -1276,37 +1207,3 @@ Warning types
|
|||
|
||||
.. versionadded:: 3.10
|
||||
:c:data:`PyExc_EncodingWarning`.
|
||||
|
||||
|
||||
Tracebacks
|
||||
==========
|
||||
|
||||
.. c:var:: PyTypeObject PyTraceBack_Type
|
||||
|
||||
Type object for traceback objects. This is available as
|
||||
:class:`types.TracebackType` in the Python layer.
|
||||
|
||||
|
||||
.. c:function:: int PyTraceBack_Check(PyObject *op)
|
||||
|
||||
Return true if *op* is a traceback object, false otherwise. This function
|
||||
does not account for subtypes.
|
||||
|
||||
|
||||
.. c:function:: int PyTraceBack_Here(PyFrameObject *f)
|
||||
|
||||
Replace the :attr:`~BaseException.__traceback__` attribute on the current
|
||||
exception with a new traceback prepending *f* to the existing chain.
|
||||
|
||||
Calling this function without an exception set is undefined behavior.
|
||||
|
||||
This function returns ``0`` on success, and returns ``-1`` with an
|
||||
exception set on failure.
|
||||
|
||||
|
||||
.. c:function:: int PyTraceBack_Print(PyObject *tb, PyObject *f)
|
||||
|
||||
Write the traceback *tb* into the file *f*.
|
||||
|
||||
This function returns ``0`` on success, and returns ``-1`` with an
|
||||
exception set on failure.
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ Defining extension modules
|
|||
A C extension for CPython is a shared library (for example, a ``.so`` file
|
||||
on Linux, ``.pyd`` DLL on Windows), which is loadable into the Python process
|
||||
(for example, it is compiled with compatible compiler settings), and which
|
||||
exports an :dfn:`export hook` function (or an
|
||||
old-style :ref:`initialization function <extension-pyinit>`).
|
||||
exports an :ref:`initialization function <extension-export-hook>`.
|
||||
|
||||
To be importable by default (that is, by
|
||||
:py:class:`importlib.machinery.ExtensionFileLoader`),
|
||||
|
|
@ -24,127 +23,25 @@ and must be named after the module name plus an extension listed in
|
|||
One suitable tool is Setuptools, whose documentation can be found at
|
||||
https://setuptools.pypa.io/en/latest/setuptools.html.
|
||||
|
||||
.. _extension-export-hook:
|
||||
Normally, the initialization function returns a module definition initialized
|
||||
using :c:func:`PyModuleDef_Init`.
|
||||
This allows splitting the creation process into several phases:
|
||||
|
||||
Extension export hook
|
||||
.....................
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
Support for the :samp:`PyModExport_{<name>}` export hook was added in Python
|
||||
3.15. The older way of defining modules is still available: consult either
|
||||
the :ref:`extension-pyinit` section or earlier versions of this
|
||||
documentation if you plan to support earlier Python versions.
|
||||
|
||||
The export hook must be an exported function with the following signature:
|
||||
|
||||
.. c:function:: PyModuleDef_Slot *PyModExport_modulename(void)
|
||||
|
||||
For modules with ASCII-only names, the :ref:`export hook <extension-export-hook>`
|
||||
must be named :samp:`PyModExport_{<name>}`,
|
||||
with ``<name>`` replaced by the module's name.
|
||||
|
||||
For non-ASCII module names, the export hook must instead be named
|
||||
:samp:`PyModExportU_{<name>}` (note the ``U``), with ``<name>`` encoded using
|
||||
Python's *punycode* encoding with hyphens replaced by underscores. In Python:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def hook_name(name):
|
||||
try:
|
||||
suffix = b'_' + name.encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
|
||||
return b'PyModExport' + suffix
|
||||
|
||||
The export hook returns an array of :c:type:`PyModuleDef_Slot` entries,
|
||||
terminated by an entry with a slot ID of ``0``.
|
||||
These slots describe how the module should be created and initialized.
|
||||
|
||||
This array must remain valid and constant until interpreter shutdown.
|
||||
Typically, it should use ``static`` storage.
|
||||
Prefer using the :c:macro:`Py_mod_create` and :c:macro:`Py_mod_exec` slots
|
||||
for any dynamic behavior.
|
||||
|
||||
The export hook may return ``NULL`` with an exception set to signal failure.
|
||||
|
||||
It is recommended to define the export hook function using a helper macro:
|
||||
|
||||
.. c:macro:: PyMODEXPORT_FUNC
|
||||
|
||||
Declare an extension module export hook.
|
||||
This macro:
|
||||
|
||||
* specifies the :c:expr:`PyModuleDef_Slot*` return type,
|
||||
* adds any special linkage declarations required by the platform, and
|
||||
* for C++, declares the function as ``extern "C"``.
|
||||
|
||||
For example, a module called ``spam`` would be defined like this::
|
||||
|
||||
PyABIInfo_VAR(abi_info);
|
||||
|
||||
static PyModuleDef_Slot spam_slots[] = {
|
||||
{Py_mod_abi, &abi_info},
|
||||
{Py_mod_name, "spam"},
|
||||
{Py_mod_init, spam_init_function},
|
||||
...
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
PyMODEXPORT_FUNC
|
||||
PyModExport_spam(void)
|
||||
{
|
||||
return spam_slots;
|
||||
}
|
||||
|
||||
The export hook is typically the only non-\ ``static``
|
||||
item defined in the module's C source.
|
||||
|
||||
The hook should be kept short -- ideally, one line as above.
|
||||
If you do need to use Python C API in this function, it is recommended to call
|
||||
``PyABIInfo_Check(&abi_info, "modulename")`` first to raise an exception,
|
||||
rather than crash, in common cases of ABI mismatch.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
It is possible to export multiple modules from a single shared library by
|
||||
defining multiple export hooks.
|
||||
However, importing them requires a custom importer or suitably named
|
||||
copies/links of the extension file, because Python's import machinery only
|
||||
finds the function corresponding to the filename.
|
||||
See the `Multiple modules in one library <https://peps.python.org/pep-0489/#multiple-modules-in-one-library>`__
|
||||
section in :pep:`489` for details.
|
||||
|
||||
|
||||
.. _multi-phase-initialization:
|
||||
|
||||
Multi-phase initialization
|
||||
..........................
|
||||
|
||||
The process of creating an extension module follows several phases:
|
||||
|
||||
- Python finds and calls the export hook to get information on how to
|
||||
create the module.
|
||||
- Before any substantial code is executed, Python can determine which
|
||||
capabilities the module supports, and it can adjust the environment or
|
||||
refuse loading an incompatible extension.
|
||||
Slots like :c:data:`Py_mod_abi`, :c:data:`Py_mod_gil` and
|
||||
:c:data:`Py_mod_multiple_interpreters` influence this step.
|
||||
- By default, Python itself then creates the module object -- that is, it does
|
||||
the equivalent of calling :py:meth:`~object.__new__` when creating an object.
|
||||
This step can be overridden using the :c:data:`Py_mod_create` slot.
|
||||
- Python sets initial module attributes like :attr:`~module.__package__` and
|
||||
:attr:`~module.__loader__`, and inserts the module object into
|
||||
:py:attr:`sys.modules`.
|
||||
- Afterwards, the module object is initialized in an extension-specific way
|
||||
-- the equivalent of :py:meth:`~object.__init__` when creating an object,
|
||||
or of executing top-level code in a Python-language module.
|
||||
The behavior is specified using the :c:data:`Py_mod_exec` slot.
|
||||
- By default, Python itself creates the module object -- that is, it does
|
||||
the equivalent of :py:meth:`object.__new__` for classes.
|
||||
It also sets initial attributes like :attr:`~module.__package__` and
|
||||
:attr:`~module.__loader__`.
|
||||
- Afterwards, the module object is initialized using extension-specific
|
||||
code -- the equivalent of :py:meth:`~object.__init__` on classes.
|
||||
|
||||
This is called *multi-phase initialization* to distinguish it from the legacy
|
||||
(but still supported) :ref:`single-phase initialization <single-phase-initialization>`,
|
||||
where an initialization function returns a fully constructed module.
|
||||
(but still supported) *single-phase initialization* scheme,
|
||||
where the initialization function returns a fully constructed module.
|
||||
See the :ref:`single-phase-initialization section below <single-phase-initialization>`
|
||||
for details.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
|
|
@ -156,7 +53,7 @@ Multiple module instances
|
|||
|
||||
By default, extension modules are not singletons.
|
||||
For example, if the :py:attr:`sys.modules` entry is removed and the module
|
||||
is re-imported, a new module object is created and, typically, populated with
|
||||
is re-imported, a new module object is created, and typically populated with
|
||||
fresh method and type objects.
|
||||
The old module is subject to normal garbage collection.
|
||||
This mirrors the behavior of pure-Python modules.
|
||||
|
|
@ -186,34 +83,36 @@ A module may also be limited to the main interpreter using
|
|||
the :c:data:`Py_mod_multiple_interpreters` slot.
|
||||
|
||||
|
||||
.. _extension-pyinit:
|
||||
.. _extension-export-hook:
|
||||
|
||||
``PyInit`` function
|
||||
...................
|
||||
Initialization function
|
||||
.......................
|
||||
|
||||
.. deprecated:: 3.15
|
||||
|
||||
This functionality is :term:`soft deprecated`.
|
||||
It 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:
|
||||
The initialization function defined by an extension module has the
|
||||
following signature:
|
||||
|
||||
.. c:function:: PyObject* PyInit_modulename(void)
|
||||
|
||||
Its name should be :samp:`PyInit_{<name>}`, with ``<name>`` replaced by the
|
||||
name of the module.
|
||||
For non-ASCII module names, use :samp:`PyInitU_{<name>}` instead, with
|
||||
``<name>`` encoded in the same way as for the
|
||||
:ref:`export hook <extension-export-hook>` (that is, using Punycode
|
||||
with underscores).
|
||||
|
||||
If a module exports both :samp:`PyInit_{<name>}` and
|
||||
:samp:`PyModExport_{<name>}`, the :samp:`PyInit_{<name>}` function
|
||||
is ignored.
|
||||
For modules with ASCII-only names, the function must instead be named
|
||||
:samp:`PyInit_{<name>}`, with ``<name>`` replaced by the name of the module.
|
||||
When using :ref:`multi-phase-initialization`, non-ASCII module names
|
||||
are allowed. In this case, the initialization function name is
|
||||
:samp:`PyInitU_{<name>}`, with ``<name>`` encoded using Python's
|
||||
*punycode* encoding with hyphens replaced by underscores. In Python:
|
||||
|
||||
Like with :c:macro:`PyMODEXPORT_FUNC`, it is recommended to define the
|
||||
initialization function using a helper macro:
|
||||
.. code-block:: python
|
||||
|
||||
def initfunc_name(name):
|
||||
try:
|
||||
suffix = b'_' + name.encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
|
||||
return b'PyInit' + suffix
|
||||
|
||||
It is recommended to define the initialization function using a helper macro:
|
||||
|
||||
.. c:macro:: PyMODINIT_FUNC
|
||||
|
||||
|
|
@ -224,34 +123,6 @@ initialization function using a helper macro:
|
|||
* adds any special linkage declarations required by the platform, and
|
||||
* for C++, declares the function as ``extern "C"``.
|
||||
|
||||
|
||||
Normally, the initialization function (``PyInit_modulename``) returns
|
||||
a :c:type:`PyModuleDef` instance with non-``NULL``
|
||||
:c:member:`~PyModuleDef.m_slots`. This allows Python to use
|
||||
:ref:`multi-phase initialization <multi-phase-initialization>`.
|
||||
|
||||
Before it is returned, the ``PyModuleDef`` instance must be initialized
|
||||
using the following function:
|
||||
|
||||
.. c:function:: PyObject* PyModuleDef_Init(PyModuleDef *def)
|
||||
|
||||
Ensure a module definition is a properly initialized Python object that
|
||||
correctly reports its type and a reference count.
|
||||
|
||||
Return *def* cast to ``PyObject*``, or ``NULL`` if an error occurred.
|
||||
|
||||
Calling this function is required before returning a :c:type:`PyModuleDef`
|
||||
from a module initialization function.
|
||||
It should not be used in other contexts.
|
||||
|
||||
Note that Python assumes that ``PyModuleDef`` structures are statically
|
||||
allocated.
|
||||
This function may return either a new reference or a borrowed one;
|
||||
this reference must not be released.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
|
||||
For example, a module called ``spam`` would be defined like this::
|
||||
|
||||
static struct PyModuleDef spam_module = {
|
||||
|
|
@ -266,23 +137,59 @@ For example, a module called ``spam`` would be defined like this::
|
|||
return PyModuleDef_Init(&spam_module);
|
||||
}
|
||||
|
||||
It is possible to export multiple modules from a single shared library by
|
||||
defining multiple initialization functions. However, importing them requires
|
||||
using symbolic links or a custom importer, because by default only the
|
||||
function corresponding to the filename is found.
|
||||
See the `Multiple modules in one library <https://peps.python.org/pep-0489/#multiple-modules-in-one-library>`__
|
||||
section in :pep:`489` for details.
|
||||
|
||||
The initialization function is typically the only non-\ ``static``
|
||||
item defined in the module's C source.
|
||||
|
||||
|
||||
.. _multi-phase-initialization:
|
||||
|
||||
Multi-phase initialization
|
||||
..........................
|
||||
|
||||
Normally, the :ref:`initialization function <extension-export-hook>`
|
||||
(``PyInit_modulename``) returns a :c:type:`PyModuleDef` instance with
|
||||
non-``NULL`` :c:member:`~PyModuleDef.m_slots`.
|
||||
Before it is returned, the ``PyModuleDef`` instance must be initialized
|
||||
using the following function:
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyModuleDef_Init(PyModuleDef *def)
|
||||
|
||||
Ensure a module definition is a properly initialized Python object that
|
||||
correctly reports its type and a reference count.
|
||||
|
||||
Return *def* cast to ``PyObject*``, or ``NULL`` if an error occurred.
|
||||
|
||||
Calling this function is required for :ref:`multi-phase-initialization`.
|
||||
It should not be used in other contexts.
|
||||
|
||||
Note that Python assumes that ``PyModuleDef`` structures are statically
|
||||
allocated.
|
||||
This function may return either a new reference or a borrowed one;
|
||||
this reference must not be released.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
|
||||
.. _single-phase-initialization:
|
||||
|
||||
Legacy single-phase initialization
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
..................................
|
||||
|
||||
.. deprecated:: 3.15
|
||||
|
||||
Single-phase initialization is :term:`soft deprecated`.
|
||||
It is a legacy mechanism to initialize extension
|
||||
.. attention::
|
||||
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.
|
||||
|
||||
However, there are no plans to remove support for it.
|
||||
|
||||
In single-phase initialization, the old-style
|
||||
:ref:`initialization function <extension-pyinit>` (``PyInit_modulename``)
|
||||
In single-phase initialization, the
|
||||
:ref:`initialization function <extension-export-hook>` (``PyInit_modulename``)
|
||||
should create, populate and return a module object.
|
||||
This is typically done using :c:func:`PyModule_Create` and functions like
|
||||
:c:func:`PyModule_AddObjectRef`.
|
||||
|
|
@ -335,8 +242,6 @@ in the following ways:
|
|||
* Single-phase modules support module lookup functions like
|
||||
:c:func:`PyState_FindModule`.
|
||||
|
||||
* The module's :c:member:`PyModuleDef.m_slots` must be NULL.
|
||||
|
||||
.. [#testsinglephase] ``_testsinglephase`` is an internal module used
|
||||
in CPython's self-test suite; your installation may or may not
|
||||
include it.
|
||||
|
|
|
|||
|
|
@ -93,29 +93,6 @@ the :mod:`io` APIs instead.
|
|||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyFile_OpenCodeObject(PyObject *path)
|
||||
|
||||
Open *path* with the mode ``'rb'``. *path* must be a Python :class:`str`
|
||||
object. The behavior of this function may be overridden by
|
||||
:c:func:`PyFile_SetOpenCodeHook` to allow for some preprocessing of the
|
||||
text.
|
||||
|
||||
This is analogous to :func:`io.open_code` in Python.
|
||||
|
||||
On success, this function returns a :term:`strong reference` to a Python
|
||||
file object. On failure, this function returns ``NULL`` with an exception
|
||||
set.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyFile_OpenCode(const char *path)
|
||||
|
||||
Similar to :c:func:`PyFile_OpenCodeObject`, but *path* is a
|
||||
UTF-8 encoded :c:expr:`const char*`.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
.. c:function:: int PyFile_WriteObject(PyObject *obj, PyObject *p, int flags)
|
||||
|
||||
|
|
|
|||
|
|
@ -78,111 +78,6 @@ Floating-Point Objects
|
|||
Return the minimum normalized positive float *DBL_MIN* as C :c:expr:`double`.
|
||||
|
||||
|
||||
.. c:macro:: Py_INFINITY
|
||||
|
||||
This macro expands a to 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`.
|
||||
|
||||
|
||||
.. c:macro:: Py_NAN
|
||||
|
||||
This macro expands a to 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
|
||||
the C11 standard ``<math.h>`` header.
|
||||
|
||||
|
||||
.. c:macro:: Py_HUGE_VAL
|
||||
|
||||
Equivalent to :c:macro:`!INFINITY`.
|
||||
|
||||
.. deprecated:: 3.14
|
||||
The macro is :term:`soft deprecated`.
|
||||
|
||||
|
||||
.. c:macro:: Py_MATH_E
|
||||
|
||||
The definition (accurate for a :c:expr:`double` type) of the :data:`math.e` constant.
|
||||
|
||||
|
||||
.. c:macro:: Py_MATH_El
|
||||
|
||||
High precision (long double) definition of :data:`~math.e` constant.
|
||||
|
||||
.. deprecated-removed:: 3.15 3.20
|
||||
|
||||
|
||||
.. c:macro:: Py_MATH_PI
|
||||
|
||||
The definition (accurate for a :c:expr:`double` type) of the :data:`math.pi` constant.
|
||||
|
||||
|
||||
.. c:macro:: Py_MATH_PIl
|
||||
|
||||
High precision (long double) definition of :data:`~math.pi` constant.
|
||||
|
||||
.. deprecated-removed:: 3.15 3.20
|
||||
|
||||
|
||||
.. c:macro:: Py_MATH_TAU
|
||||
|
||||
The definition (accurate for a :c:expr:`double` type) of the :data:`math.tau` constant.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
|
||||
|
||||
.. c:macro:: Py_RETURN_NAN
|
||||
|
||||
Return :data:`math.nan` from a function.
|
||||
|
||||
On most platforms, this is equivalent to ``return PyFloat_FromDouble(NAN)``.
|
||||
|
||||
|
||||
.. c:macro:: Py_RETURN_INF(sign)
|
||||
|
||||
Return :data:`math.inf` or :data:`-math.inf <math.inf>` from a function,
|
||||
depending on the sign of *sign*.
|
||||
|
||||
On most platforms, this is equivalent to the following::
|
||||
|
||||
return PyFloat_FromDouble(copysign(INFINITY, sign));
|
||||
|
||||
|
||||
.. c:macro:: Py_IS_FINITE(X)
|
||||
|
||||
Return ``1`` if the given floating-point number *X* is finite,
|
||||
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.
|
||||
|
||||
|
||||
.. c:macro:: Py_IS_INFINITY(X)
|
||||
|
||||
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.
|
||||
|
||||
|
||||
.. c:macro:: Py_IS_NAN(X)
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Pack and Unpack functions
|
||||
-------------------------
|
||||
|
||||
|
|
@ -201,8 +96,8 @@ NaNs (if such things exist on the platform) isn't handled correctly, and
|
|||
attempting to unpack a bytes string containing an IEEE INF or NaN will raise an
|
||||
exception.
|
||||
|
||||
Note that NaNs type may not be preserved on IEEE platforms (signaling NaN become
|
||||
quiet NaN), for example on x86 systems in 32-bit mode.
|
||||
Note that NaNs type may not be preserved on IEEE platforms (silent NaN become
|
||||
quiet), for example on x86 systems in 32-bit mode.
|
||||
|
||||
On non-IEEE platforms with more precision, or larger dynamic range, than IEEE
|
||||
754 supports, not all values can be packed; on non-IEEE platforms with less
|
||||
|
|
|
|||
|
|
@ -29,12 +29,6 @@ See also :ref:`Reflection <reflection>`.
|
|||
Previously, this type was only available after including
|
||||
``<frameobject.h>``.
|
||||
|
||||
.. c:function:: PyFrameObject *PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, PyObject *locals)
|
||||
|
||||
Create a new frame object. This function returns a :term:`strong reference`
|
||||
to the new frame object on success, and returns ``NULL`` with an exception
|
||||
set on failure.
|
||||
|
||||
.. c:function:: int PyFrame_Check(PyObject *obj)
|
||||
|
||||
Return non-zero if *obj* is a frame object.
|
||||
|
|
@ -167,57 +161,6 @@ See :pep:`667` for more information.
|
|||
|
||||
Return non-zero if *obj* is a frame :func:`locals` proxy.
|
||||
|
||||
|
||||
Legacy Local Variable APIs
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
These APIs are :term:`soft deprecated`. As of Python 3.13, they do nothing.
|
||||
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
|
||||
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
|
||||
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
|
||||
This function now does nothing.
|
||||
|
||||
|
||||
.. seealso::
|
||||
:pep:`667`
|
||||
|
||||
|
||||
Internal Frames
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
|||
|
|
@ -102,15 +102,6 @@ There are a few functions specific to Python functions.
|
|||
dictionary of arguments or ``NULL``.
|
||||
|
||||
|
||||
.. c:function:: int PyFunction_SetKwDefaults(PyObject *op, PyObject *defaults)
|
||||
|
||||
Set the keyword-only argument default values of the function object *op*.
|
||||
*defaults* must be a dictionary of keyword-only arguments or ``Py_None``.
|
||||
|
||||
This function returns ``0`` on success, and returns ``-1`` with an exception
|
||||
set on failure.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyFunction_GetClosure(PyObject *op)
|
||||
|
||||
Return the closure associated with the function object *op*. This can be ``NULL``
|
||||
|
|
@ -209,7 +200,7 @@ There are a few functions specific to Python functions.
|
|||
runtime behavior depending on optimization decisions, it does not change
|
||||
the semantics of the Python code being executed.
|
||||
|
||||
If *event* is ``PyFunction_EVENT_DESTROY``, taking a reference in the
|
||||
If *event* is ``PyFunction_EVENT_DESTROY``, Taking a reference in the
|
||||
callback to the about-to-be-destroyed function will resurrect it, preventing
|
||||
it from being freed at this time. When the resurrected object is destroyed
|
||||
later, any watcher callbacks active at that time will be called again.
|
||||
|
|
|
|||
|
|
@ -232,10 +232,6 @@ The :c:member:`~PyTypeObject.tp_traverse` handler must have the following type:
|
|||
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*:
|
||||
|
|
|
|||
|
|
@ -44,41 +44,3 @@ than explicitly calling :c:func:`PyGen_New` or :c:func:`PyGen_NewWithQualName`.
|
|||
with ``__name__`` and ``__qualname__`` set to *name* and *qualname*.
|
||||
A reference to *frame* is stolen by this function. The *frame* argument
|
||||
must not be ``NULL``.
|
||||
|
||||
.. c:function:: PyCodeObject* PyGen_GetCode(PyGenObject *gen)
|
||||
|
||||
Return a new :term:`strong reference` to the code object wrapped by *gen*.
|
||||
This function always succeeds.
|
||||
|
||||
|
||||
Asynchronous Generator Objects
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. seealso::
|
||||
:pep:`525`
|
||||
|
||||
.. c:var:: PyTypeObject PyAsyncGen_Type
|
||||
|
||||
The type object corresponding to asynchronous generator objects. This is
|
||||
available as :class:`types.AsyncGeneratorType` in the Python layer.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
|
||||
.. c:function:: PyObject *PyAsyncGen_New(PyFrameObject *frame, PyObject *name, PyObject *qualname)
|
||||
|
||||
Create a new asynchronous generator wrapping *frame*, with ``__name__`` and
|
||||
``__qualname__`` set to *name* and *qualname*. *frame* is stolen by this
|
||||
function and must not be ``NULL``.
|
||||
|
||||
On success, this function returns a :term:`strong reference` to the
|
||||
new asynchronous generator. On failure, this function returns ``NULL``
|
||||
with an exception set.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
|
||||
.. c:function:: int PyAsyncGen_CheckExact(PyObject *op)
|
||||
|
||||
Return true if *op* is an asynchronous generator object, false otherwise.
|
||||
This function always succeeds.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
|
|
|
|||
|
|
@ -11,98 +11,42 @@ See also the :c:member:`PyTypeObject.tp_hash` member and :ref:`numeric-hash`.
|
|||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
|
||||
.. c:type:: Py_uhash_t
|
||||
|
||||
Hash value type: unsigned integer.
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
|
||||
.. c:macro:: Py_HASH_ALGORITHM
|
||||
|
||||
A numerical value indicating the algorithm for hashing of :class:`str`,
|
||||
:class:`bytes`, and :class:`memoryview`.
|
||||
|
||||
The algorithm name is exposed by :data:`sys.hash_info.algorithm`.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
|
||||
.. c:macro:: Py_HASH_FNV
|
||||
Py_HASH_SIPHASH24
|
||||
Py_HASH_SIPHASH13
|
||||
|
||||
Numerical values to compare to :c:macro:`Py_HASH_ALGORITHM` to determine
|
||||
which algorithm is used for hashing. The hash algorithm can be configured
|
||||
via the configure :option:`--with-hash-algorithm` option.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
Add :c:macro:`!Py_HASH_FNV` and :c:macro:`!Py_HASH_SIPHASH24`.
|
||||
|
||||
.. versionadded:: 3.11
|
||||
Add :c:macro:`!Py_HASH_SIPHASH13`.
|
||||
|
||||
|
||||
.. c:macro:: Py_HASH_CUTOFF
|
||||
|
||||
Buffers of length in range ``[1, Py_HASH_CUTOFF)`` are hashed using DJBX33A
|
||||
instead of the algorithm described by :c:macro:`Py_HASH_ALGORITHM`.
|
||||
|
||||
- A :c:macro:`!Py_HASH_CUTOFF` of 0 disables the optimization.
|
||||
- :c:macro:`!Py_HASH_CUTOFF` must be non-negative and less or equal than 7.
|
||||
|
||||
32-bit platforms should use a cutoff smaller than 64-bit platforms because
|
||||
it is easier to create colliding strings. A cutoff of 7 on 64-bit platforms
|
||||
and 5 on 32-bit platforms should provide a decent safety margin.
|
||||
|
||||
This corresponds to the :data:`sys.hash_info.cutoff` constant.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
|
||||
.. c:macro:: PyHASH_MODULUS
|
||||
|
||||
The `Mersenne prime <https://en.wikipedia.org/wiki/Mersenne_prime>`_ ``P = 2**n -1``,
|
||||
used for numeric hash scheme.
|
||||
|
||||
This corresponds to the :data:`sys.hash_info.modulus` constant.
|
||||
The `Mersenne prime <https://en.wikipedia.org/wiki/Mersenne_prime>`_ ``P = 2**n -1``, used for numeric hash scheme.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:macro:: PyHASH_BITS
|
||||
|
||||
The exponent ``n`` of ``P`` in :c:macro:`PyHASH_MODULUS`.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:macro:: PyHASH_MULTIPLIER
|
||||
|
||||
Prime multiplier used in string and various other hashes.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:macro:: PyHASH_INF
|
||||
|
||||
The hash value returned for a positive infinity.
|
||||
|
||||
This corresponds to the :data:`sys.hash_info.inf` constant.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:macro:: PyHASH_IMAG
|
||||
|
||||
The multiplier used for the imaginary part of a complex number.
|
||||
|
||||
This corresponds to the :data:`sys.hash_info.imag` constant.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:type:: PyHash_FuncDef
|
||||
|
||||
Hash function definition used by :c:func:`PyHash_GetFuncDef`.
|
||||
|
|
@ -115,20 +59,14 @@ See also the :c:member:`PyTypeObject.tp_hash` member and :ref:`numeric-hash`.
|
|||
|
||||
Hash function name (UTF-8 encoded string).
|
||||
|
||||
This corresponds to the :data:`sys.hash_info.algorithm` constant.
|
||||
|
||||
.. c:member:: const int hash_bits
|
||||
|
||||
Internal size of the hash value in bits.
|
||||
|
||||
This corresponds to the :data:`sys.hash_info.hash_bits` constant.
|
||||
|
||||
.. c:member:: const int seed_bits
|
||||
|
||||
Size of seed input in bits.
|
||||
|
||||
This corresponds to the :data:`sys.hash_info.seed_bits` constant.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,8 @@ Importing Modules
|
|||
of :class:`~importlib.machinery.SourceFileLoader` otherwise.
|
||||
|
||||
The module's :attr:`~module.__file__` attribute will be set to the code
|
||||
object's :attr:`~codeobject.co_filename`.
|
||||
object's :attr:`~codeobject.co_filename`. If applicable,
|
||||
:attr:`~module.__cached__` will also be set.
|
||||
|
||||
This function will reload the module if it was already imported. See
|
||||
:c:func:`PyImport_ReloadModule` for the intended way to reload a module.
|
||||
|
|
@ -141,13 +142,10 @@ Importing Modules
|
|||
:c:func:`PyImport_ExecCodeModuleWithPathnames`.
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
The setting of ``__cached__`` and :attr:`~module.__loader__`
|
||||
The setting of :attr:`~module.__cached__` and :attr:`~module.__loader__`
|
||||
is deprecated. See :class:`~importlib.machinery.ModuleSpec` for
|
||||
alternatives.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
``__cached__`` is no longer set.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyImport_ExecCodeModuleEx(const char *name, PyObject *co, const char *pathname)
|
||||
|
||||
|
|
@ -159,19 +157,16 @@ Importing Modules
|
|||
|
||||
.. c:function:: PyObject* PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname, PyObject *cpathname)
|
||||
|
||||
Like :c:func:`PyImport_ExecCodeModuleEx`, but the path to any compiled file
|
||||
via *cpathname* is used appropriately when non-``NULL``. Of the three
|
||||
functions, this is the preferred one to use.
|
||||
Like :c:func:`PyImport_ExecCodeModuleEx`, but the :attr:`~module.__cached__`
|
||||
attribute of the module object is set to *cpathname* if it is
|
||||
non-``NULL``. Of the three functions, this is the preferred one to use.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
Setting ``__cached__`` is deprecated. See
|
||||
Setting :attr:`~module.__cached__` is deprecated. See
|
||||
:class:`~importlib.machinery.ModuleSpec` for alternatives.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
``__cached__`` no longer set.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyImport_ExecCodeModuleWithPathnames(const char *name, PyObject *co, const char *pathname, const char *cpathname)
|
||||
|
||||
|
|
@ -319,13 +314,6 @@ Importing Modules
|
|||
initialization.
|
||||
|
||||
|
||||
.. c:var:: struct _inittab *PyImport_Inittab
|
||||
|
||||
The table of built-in modules used by Python initialization. Do not use this directly;
|
||||
use :c:func:`PyImport_AppendInittab` and :c:func:`PyImport_ExtendInittab`
|
||||
instead.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyImport_ImportModuleAttr(PyObject *mod_name, PyObject *attr_name)
|
||||
|
||||
Import the module *mod_name* and get its attribute *attr_name*.
|
||||
|
|
@ -345,24 +333,3 @@ Importing Modules
|
|||
strings instead of Python :class:`str` objects.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
.. c:function:: PyObject* PyImport_CreateModuleFromInitfunc(PyObject *spec, PyObject* (*initfunc)(void))
|
||||
|
||||
This function is a building block that enables embedders to implement
|
||||
the :py:meth:`~importlib.abc.Loader.create_module` step of custom
|
||||
static extension importers (e.g. of statically-linked extensions).
|
||||
|
||||
*spec* must be a :class:`~importlib.machinery.ModuleSpec` object.
|
||||
|
||||
*initfunc* must be an :ref:`initialization function <extension-export-hook>`,
|
||||
the same as for :c:func:`PyImport_AppendInittab`.
|
||||
|
||||
On success, create and return a module object.
|
||||
This module will not be initialized; call :c:func:`PyModule_Exec`
|
||||
to initialize it.
|
||||
(Custom importers should do this in their
|
||||
:py:meth:`~importlib.abc.Loader.exec_module` method.)
|
||||
|
||||
On error, return NULL with an exception set.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
|
|
|||
|
|
@ -1366,43 +1366,6 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
|
|||
.. 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:: PyInterpreterState* PyInterpreterState_Get(void)
|
||||
|
||||
Get the current interpreter.
|
||||
|
|
@ -1717,8 +1680,7 @@ function. You can create and destroy them using the following functions:
|
|||
Only C-level static and global variables are shared between these
|
||||
module objects.
|
||||
|
||||
* For modules using legacy
|
||||
:ref:`single-phase initialization <single-phase-initialization>`,
|
||||
* For modules using 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.
|
||||
|
|
@ -1892,25 +1854,6 @@ pointer and a void pointer argument.
|
|||
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.
|
||||
|
||||
|
||||
.. _profiling:
|
||||
|
||||
Profiling and Tracing
|
||||
|
|
@ -2197,7 +2140,7 @@ 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.
|
||||
when calling these functions; they suppl their own locking.
|
||||
|
||||
Note that :file:`Python.h` does not include the declaration of the TLS APIs,
|
||||
you need to include :file:`pythread.h` to use thread-local storage.
|
||||
|
|
@ -2540,220 +2483,3 @@ code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`.
|
|||
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`.
|
||||
|
||||
|
||||
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`
|
||||
|
||||
|
||||
.. 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`.
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ Error Handling
|
|||
* Set *\*err_msg* and return ``1`` if an error is set.
|
||||
* Set *\*err_msg* to ``NULL`` and return ``0`` otherwise.
|
||||
|
||||
An error message is a UTF-8 encoded string.
|
||||
An error message is an UTF-8 encoded string.
|
||||
|
||||
If *config* has an exit code, format the exit code as an error
|
||||
message.
|
||||
|
|
|
|||
|
|
@ -107,46 +107,6 @@ header files properly declare the entry points to be ``extern "C"``. As a result
|
|||
there is no need to do anything special to use the API from C++.
|
||||
|
||||
|
||||
.. _capi-system-includes:
|
||||
|
||||
System includes
|
||||
---------------
|
||||
|
||||
:file:`Python.h` includes several standard header files.
|
||||
C extensions should include the standard headers that they use,
|
||||
and should not rely on these implicit includes.
|
||||
The implicit includes are:
|
||||
|
||||
* ``<assert.h>``
|
||||
* ``<intrin.h>`` (on Windows)
|
||||
* ``<inttypes.h>``
|
||||
* ``<limits.h>``
|
||||
* ``<math.h>``
|
||||
* ``<stdarg.h>``
|
||||
* ``<wchar.h>``
|
||||
* ``<sys/types.h>`` (if present)
|
||||
|
||||
The following are included for backwards compatibility, unless using
|
||||
:ref:`Limited API <limited-c-api>` 3.13 or newer:
|
||||
|
||||
* ``<ctype.h>``
|
||||
* ``<unistd.h>`` (on POSIX)
|
||||
|
||||
The following are included for backwards compatibility, unless using
|
||||
:ref:`Limited API <limited-c-api>` 3.11 or newer:
|
||||
|
||||
* ``<errno.h>``
|
||||
* ``<stdio.h>``
|
||||
* ``<stdlib.h>``
|
||||
* ``<string.h>``
|
||||
|
||||
.. note::
|
||||
|
||||
Since Python may define some pre-processor definitions which affect the standard
|
||||
headers on some systems, you *must* include :file:`Python.h` before any standard
|
||||
headers are included.
|
||||
|
||||
|
||||
Useful macros
|
||||
=============
|
||||
|
||||
|
|
@ -161,10 +121,6 @@ complete listing.
|
|||
|
||||
Return the absolute value of ``x``.
|
||||
|
||||
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.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. c:macro:: Py_ALWAYS_INLINE
|
||||
|
|
@ -211,17 +167,6 @@ complete listing.
|
|||
Like ``getenv(s)``, but returns ``NULL`` if :option:`-E` was passed on the
|
||||
command line (see :c:member:`PyConfig.use_environment`).
|
||||
|
||||
.. 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_MAX(x, y)
|
||||
|
||||
Return the maximum value between ``x`` and ``y``.
|
||||
|
|
@ -234,14 +179,6 @@ complete listing.
|
|||
|
||||
.. 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``.
|
||||
|
|
@ -296,32 +233,9 @@ complete listing.
|
|||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
.. 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.
|
||||
|
||||
For example::
|
||||
|
||||
Py_BUILD_ASSERT(sizeof(PyTime_t) == sizeof(int64_t));
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. c:macro:: Py_BUILD_ASSERT_EXPR(cond)
|
||||
|
||||
Asserts a compile-time condition *cond*, as an expression that evaluates to ``0``.
|
||||
The build will fail if the condition is false or cannot be evaluated at compile time.
|
||||
|
||||
For example::
|
||||
|
||||
#define foo_to_char(foo) \
|
||||
((char *)(foo) + Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0))
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. c:macro:: PyDoc_STRVAR(name, str)
|
||||
|
||||
Creates a variable with name *name* that can be used in docstrings.
|
||||
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
|
||||
|
|
@ -353,28 +267,6 @@ complete listing.
|
|||
{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.");
|
||||
|
||||
.. c:macro:: Py_ARRAY_LENGTH(array)
|
||||
|
||||
Compute the length of a statically allocated C array at compile time.
|
||||
|
||||
The *array* argument must be a C array with a size known at compile time.
|
||||
Passing an array with an unknown size, such as a heap-allocated array,
|
||||
will result in a compilation error on some compilers, or otherwise produce
|
||||
incorrect results.
|
||||
|
||||
This is roughly equivalent to::
|
||||
|
||||
sizeof(array) / sizeof((array)[0])
|
||||
|
||||
|
||||
.. _api-objects:
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,6 @@ There are two functions specifically for working with iterators.
|
|||
|
||||
- ``PYGEN_RETURN`` if iterator returns. Return value is returned via *presult*.
|
||||
- ``PYGEN_NEXT`` if iterator yields. Yielded value is returned via *presult*.
|
||||
- ``PYGEN_ERROR`` if iterator has raised an exception. *presult* is set to ``NULL``.
|
||||
- ``PYGEN_ERROR`` if iterator has raised and exception. *presult* is set to ``NULL``.
|
||||
|
||||
.. versionadded:: 3.10
|
||||
|
|
|
|||
|
|
@ -50,72 +50,3 @@ sentinel value is returned.
|
|||
callable object that can be called with no parameters; each call to it should
|
||||
return the next item in the iteration. When *callable* returns a value equal to
|
||||
*sentinel*, the iteration will be terminated.
|
||||
|
||||
|
||||
Range Objects
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
.. c:var:: PyTypeObject PyRange_Type
|
||||
|
||||
The type object for :class:`range` objects.
|
||||
|
||||
|
||||
.. c:function:: int PyRange_Check(PyObject *o)
|
||||
|
||||
Return true if the object *o* is an instance of a :class:`range` object.
|
||||
This function always succeeds.
|
||||
|
||||
|
||||
Builtin Iterator Types
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
These are built-in iteration types that are included in Python's C API, but
|
||||
provide no additional functions. They are here for completeness.
|
||||
|
||||
|
||||
.. list-table::
|
||||
:widths: auto
|
||||
:header-rows: 1
|
||||
|
||||
* * C type
|
||||
* Python type
|
||||
* * .. c:var:: PyTypeObject PyEnum_Type
|
||||
* :py:class:`enumerate`
|
||||
* * .. c:var:: PyTypeObject PyFilter_Type
|
||||
* :py:class:`filter`
|
||||
* * .. c:var:: PyTypeObject PyMap_Type
|
||||
* :py:class:`map`
|
||||
* * .. c:var:: PyTypeObject PyReversed_Type
|
||||
* :py:class:`reversed`
|
||||
* * .. c:var:: PyTypeObject PyZip_Type
|
||||
* :py:class:`zip`
|
||||
|
||||
|
||||
Other Iterator Objects
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. c:var:: PyTypeObject PyByteArrayIter_Type
|
||||
.. c:var:: PyTypeObject PyBytesIter_Type
|
||||
.. c:var:: PyTypeObject PyListIter_Type
|
||||
.. c:var:: PyTypeObject PyListRevIter_Type
|
||||
.. c:var:: PyTypeObject PySetIter_Type
|
||||
.. c:var:: PyTypeObject PyTupleIter_Type
|
||||
.. c:var:: PyTypeObject PyRangeIter_Type
|
||||
.. c:var:: PyTypeObject PyLongRangeIter_Type
|
||||
.. c:var:: PyTypeObject PyDictIterKey_Type
|
||||
.. c:var:: PyTypeObject PyDictRevIterKey_Type
|
||||
.. c:var:: PyTypeObject PyDictIterValue_Type
|
||||
.. c:var:: PyTypeObject PyDictRevIterValue_Type
|
||||
.. c:var:: PyTypeObject PyDictIterItem_Type
|
||||
.. c:var:: PyTypeObject PyDictRevIterItem_Type
|
||||
.. c:var:: PyTypeObject PyODictIter_Type
|
||||
|
||||
Type objects for iterators of various built-in objects.
|
||||
|
||||
Do not create instances of these directly; prefer calling
|
||||
:c:func:`PyObject_GetIter` instead.
|
||||
|
||||
Note that there is no guarantee that a given built-in type uses a given iterator
|
||||
type. For example, iterating over :class:`range` will use one of two iterator
|
||||
types depending on the size of the range. Other types may start using a
|
||||
similar scheme in the future, without warning.
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
|
|||
.. impl-detail::
|
||||
|
||||
CPython keeps an array of integer objects for all integers
|
||||
between ``-5`` and ``1024``. When you create an int in that range
|
||||
between ``-5`` and ``256``. When you create an int in that range
|
||||
you actually just get back a reference to the existing object.
|
||||
|
||||
|
||||
|
|
@ -161,17 +161,6 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
|
|||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:macro:: PyLong_FromPid(pid)
|
||||
|
||||
Macro for creating a Python integer from a process identifier.
|
||||
|
||||
This can be defined as an alias to :c:func:`PyLong_FromLong` or
|
||||
:c:func:`PyLong_FromLongLong`, depending on the size of the system's
|
||||
PID type.
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
|
||||
.. c:function:: long PyLong_AsLong(PyObject *obj)
|
||||
|
||||
.. index::
|
||||
|
|
@ -586,17 +575,6 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
|
|||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:macro:: PyLong_AsPid(pid)
|
||||
|
||||
Macro for converting a Python integer into a process identifier.
|
||||
|
||||
This can be defined as an alias to :c:func:`PyLong_AsLong`,
|
||||
:c:func:`PyLong_FromLongLong`, or :c:func:`PyLong_AsInt`, depending on the
|
||||
size of the system's PID type.
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
|
||||
.. c:function:: int PyLong_GetSign(PyObject *obj, int *sign)
|
||||
|
||||
Get the sign of the integer object *obj*.
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and
|
|||
|
||||
.. note::
|
||||
|
||||
Exceptions which occur when this calls the :meth:`~object.__getitem__`
|
||||
Exceptions which occur when this calls :meth:`~object.__getitem__`
|
||||
method are silently ignored.
|
||||
For proper error handling, use :c:func:`PyMapping_HasKeyWithError`,
|
||||
:c:func:`PyMapping_GetOptionalItem` or :c:func:`PyObject_GetItem()` instead.
|
||||
|
|
@ -116,7 +116,7 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and
|
|||
|
||||
.. note::
|
||||
|
||||
Exceptions that occur when this calls the :meth:`~object.__getitem__`
|
||||
Exceptions that occur when this calls :meth:`~object.__getitem__`
|
||||
method or while creating the temporary :class:`str`
|
||||
object are silently ignored.
|
||||
For proper error handling, use :c:func:`PyMapping_HasKeyStringWithError`,
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ The following functions allow marshalled values to be read back in.
|
|||
assumes that no further objects will be read from the file, allowing it to
|
||||
aggressively load file data into memory so that the de-serialization can
|
||||
operate from data in memory rather than reading a byte at a time from the
|
||||
file. Only use this variant if you are certain that you won't be reading
|
||||
file. Only use these variant if you are certain that you won't be reading
|
||||
anything else from the file.
|
||||
|
||||
On error, sets the appropriate exception (:exc:`EOFError`, :exc:`ValueError`
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ All allocating functions belong to one of three different "domains" (see also
|
|||
strategies and are optimized for different purposes. The specific details on
|
||||
how every domain allocates memory or what internal functions each domain calls
|
||||
is considered an implementation detail, but for debugging purposes a simplified
|
||||
table can be found at :ref:`default-memory-allocators`.
|
||||
table can be found at :ref:`here <default-memory-allocators>`.
|
||||
The APIs used to allocate and free a block of memory must be from the same domain.
|
||||
For example, :c:func:`PyMem_Free` must be used to free memory allocated using :c:func:`PyMem_Malloc`.
|
||||
|
||||
|
|
|
|||
|
|
@ -13,12 +13,6 @@ A :class:`memoryview` object exposes the C level :ref:`buffer interface
|
|||
any other object.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyMemoryView_Type
|
||||
|
||||
This instance of :c:type:`PyTypeObject` represents the Python memoryview
|
||||
type. This is the same object as :class:`memoryview` in the Python layer.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyMemoryView_FromObject(PyObject *obj)
|
||||
|
||||
Create a memoryview object from an object that provides the buffer interface.
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@
|
|||
.. _moduleobjects:
|
||||
|
||||
Module Objects
|
||||
==============
|
||||
--------------
|
||||
|
||||
.. index:: pair: object; module
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyModule_Type
|
||||
|
||||
.. index:: single: ModuleType (in module types)
|
||||
|
||||
This instance of :c:type:`PyTypeObject` represents the Python module type. This
|
||||
is exposed to Python programs as :py:class:`types.ModuleType`.
|
||||
is exposed to Python programs as ``types.ModuleType``.
|
||||
|
||||
|
||||
.. c:function:: int PyModule_Check(PyObject *p)
|
||||
|
|
@ -70,9 +71,6 @@ Module Objects
|
|||
``PyObject_*`` functions rather than directly manipulate a module's
|
||||
:attr:`~object.__dict__`.
|
||||
|
||||
The returned reference is borrowed from the module; it is valid until
|
||||
the module is destroyed.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyModule_GetNameObject(PyObject *module)
|
||||
|
||||
|
|
@ -92,19 +90,18 @@ Module Objects
|
|||
Similar to :c:func:`PyModule_GetNameObject` but return the name encoded to
|
||||
``'utf-8'``.
|
||||
|
||||
The returned buffer is only valid until the module is renamed or destroyed.
|
||||
Note that Python code may rename a module by setting its :py:attr:`~module.__name__`
|
||||
attribute.
|
||||
.. c:function:: void* PyModule_GetState(PyObject *module)
|
||||
|
||||
Return the "state" of the module, that is, a pointer to the block of memory
|
||||
allocated at module creation time, or ``NULL``. See
|
||||
:c:member:`PyModuleDef.m_size`.
|
||||
|
||||
|
||||
.. c:function:: PyModuleDef* PyModule_GetDef(PyObject *module)
|
||||
|
||||
Return a pointer to the :c:type:`PyModuleDef` struct from which the module was
|
||||
created, or ``NULL`` if the module wasn't created from a definition.
|
||||
|
||||
On error, return ``NULL`` with an exception set.
|
||||
Use :c:func:`PyErr_Occurred` to tell this case apart from a missing
|
||||
:c:type:`!PyModuleDef`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyModule_GetFilenameObject(PyObject *module)
|
||||
|
||||
|
|
@ -125,116 +122,215 @@ Module Objects
|
|||
Similar to :c:func:`PyModule_GetFilenameObject` but return the filename
|
||||
encoded to 'utf-8'.
|
||||
|
||||
The returned buffer is only valid until the module's :py:attr:`~module.__file__` attribute
|
||||
is reassigned or the module is destroyed.
|
||||
|
||||
.. deprecated:: 3.2
|
||||
:c:func:`PyModule_GetFilename` raises :exc:`UnicodeEncodeError` on
|
||||
unencodable filenames, use :c:func:`PyModule_GetFilenameObject` instead.
|
||||
|
||||
|
||||
.. _pymoduledef_slot:
|
||||
.. _pymoduledef:
|
||||
|
||||
Module definition
|
||||
-----------------
|
||||
Module definitions
|
||||
------------------
|
||||
|
||||
Modules created using the C API are typically defined using an
|
||||
array of :dfn:`slots`.
|
||||
The slots provide a "description" of how a module should be created.
|
||||
The functions in the previous section work on any module object, including
|
||||
modules imported from Python code.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Modules defined using the C API typically use a *module definition*,
|
||||
:c:type:`PyModuleDef` -- a statically allocated, constant “description" of
|
||||
how a module should be created.
|
||||
|
||||
Previously, a :c:type:`PyModuleDef` struct was necessary to define modules.
|
||||
The older way of defining modules is still available: consult either the
|
||||
:ref:`pymoduledef` section or earlier versions of this documentation
|
||||
if you plan to support earlier Python versions.
|
||||
The definition is usually used to define an extension's “main” module object
|
||||
(see :ref:`extension-modules` for details).
|
||||
It is also used to
|
||||
:ref:`create extension modules dynamically <moduledef-dynamic>`.
|
||||
|
||||
The slots array is usually used to define an extension module's “main”
|
||||
module object (see :ref:`extension-modules` for details).
|
||||
It can also be used to
|
||||
:ref:`create extension modules dynamically <module-from-slots>`.
|
||||
Unlike :c:func:`PyModule_New`, the definition allows management of
|
||||
*module state* -- a piece of memory that is allocated and cleared together
|
||||
with the module object.
|
||||
Unlike the module's Python attributes, Python code cannot replace or delete
|
||||
data stored in module state.
|
||||
|
||||
Unless specified otherwise, the same slot ID may not be repeated
|
||||
in an array of slots.
|
||||
.. c:type:: PyModuleDef
|
||||
|
||||
The module definition struct, which holds all information needed to create
|
||||
a module object.
|
||||
This structure must be statically allocated (or be otherwise guaranteed
|
||||
to be valid while any modules created from it exist).
|
||||
Usually, there is only one variable of this type for each extension module.
|
||||
|
||||
.. c:member:: PyModuleDef_Base m_base
|
||||
|
||||
Always initialize this member to :c:macro:`PyModuleDef_HEAD_INIT`.
|
||||
|
||||
.. c:member:: const char *m_name
|
||||
|
||||
Name for the new module.
|
||||
|
||||
.. c:member:: const char *m_doc
|
||||
|
||||
Docstring for the module; usually a docstring variable created with
|
||||
:c:macro:`PyDoc_STRVAR` is used.
|
||||
|
||||
.. c:member:: Py_ssize_t m_size
|
||||
|
||||
Module state may be kept in a per-module memory area that can be
|
||||
retrieved with :c:func:`PyModule_GetState`, rather than in static globals.
|
||||
This makes modules safe for use in multiple sub-interpreters.
|
||||
|
||||
This memory area is allocated based on *m_size* on module creation,
|
||||
and freed when the module object is deallocated, after the
|
||||
:c:member:`~PyModuleDef.m_free` function has been called, if present.
|
||||
|
||||
Setting it to a non-negative value means that the module can be
|
||||
re-initialized and specifies the additional amount of memory it requires
|
||||
for its state.
|
||||
|
||||
Setting ``m_size`` to ``-1`` means that the module does not support
|
||||
sub-interpreters, because it has global state.
|
||||
Negative ``m_size`` is only allowed when using
|
||||
:ref:`legacy single-phase initialization <single-phase-initialization>`
|
||||
or when :ref:`creating modules dynamically <moduledef-dynamic>`.
|
||||
|
||||
See :PEP:`3121` for more details.
|
||||
|
||||
.. c:member:: PyMethodDef* m_methods
|
||||
|
||||
A pointer to a table of module-level functions, described by
|
||||
:c:type:`PyMethodDef` values. Can be ``NULL`` if no functions are present.
|
||||
|
||||
.. c:member:: PyModuleDef_Slot* m_slots
|
||||
|
||||
An array of slot definitions for multi-phase initialization, terminated by
|
||||
a ``{0, NULL}`` entry.
|
||||
When using legacy single-phase initialization, *m_slots* must be ``NULL``.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
Prior to version 3.5, this member was always set to ``NULL``,
|
||||
and was defined as:
|
||||
|
||||
.. c:member:: inquiry m_reload
|
||||
|
||||
.. c:member:: traverseproc m_traverse
|
||||
|
||||
A traversal function to call during GC traversal of the module object, or
|
||||
``NULL`` if not needed.
|
||||
|
||||
This function is not called if the module state was requested but is not
|
||||
allocated yet. This is the case immediately after the module is created
|
||||
and before the module is executed (:c:data:`Py_mod_exec` function). More
|
||||
precisely, this function is not called if :c:member:`~PyModuleDef.m_size` is greater
|
||||
than 0 and the module state (as returned by :c:func:`PyModule_GetState`)
|
||||
is ``NULL``.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
No longer called before the module state is allocated.
|
||||
|
||||
.. c:member:: inquiry m_clear
|
||||
|
||||
A clear function to call during GC clearing of the module object, or
|
||||
``NULL`` if not needed.
|
||||
|
||||
This function is not called if the module state was requested but is not
|
||||
allocated yet. This is the case immediately after the module is created
|
||||
and before the module is executed (:c:data:`Py_mod_exec` function). More
|
||||
precisely, this function is not called if :c:member:`~PyModuleDef.m_size` is greater
|
||||
than 0 and the module state (as returned by :c:func:`PyModule_GetState`)
|
||||
is ``NULL``.
|
||||
|
||||
Like :c:member:`PyTypeObject.tp_clear`, this function is not *always*
|
||||
called before a module is deallocated. For example, when reference
|
||||
counting is enough to determine that an object is no longer used,
|
||||
the cyclic garbage collector is not involved and
|
||||
:c:member:`~PyModuleDef.m_free` is called directly.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
No longer called before the module state is allocated.
|
||||
|
||||
.. c:member:: freefunc m_free
|
||||
|
||||
A function to call during deallocation of the module object, or ``NULL``
|
||||
if not needed.
|
||||
|
||||
This function is not called if the module state was requested but is not
|
||||
allocated yet. This is the case immediately after the module is created
|
||||
and before the module is executed (:c:data:`Py_mod_exec` function). More
|
||||
precisely, this function is not called if :c:member:`~PyModuleDef.m_size` is greater
|
||||
than 0 and the module state (as returned by :c:func:`PyModule_GetState`)
|
||||
is ``NULL``.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
No longer called before the module state is allocated.
|
||||
|
||||
|
||||
Module slots
|
||||
............
|
||||
|
||||
.. c:type:: PyModuleDef_Slot
|
||||
|
||||
.. c:member:: int slot
|
||||
|
||||
A slot ID, chosen from the available ``Py_mod_*`` values explained below.
|
||||
|
||||
An ID of 0 marks the end of a :c:type:`!PyModuleDef_Slot` array.
|
||||
A slot ID, chosen from the available values explained below.
|
||||
|
||||
.. c:member:: void* value
|
||||
|
||||
Value of the slot, whose meaning depends on the slot ID.
|
||||
|
||||
The value may not be NULL.
|
||||
To leave a slot out, omit the :c:type:`PyModuleDef_Slot` entry entirely.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
The available slot types are:
|
||||
|
||||
Metadata slots
|
||||
..............
|
||||
.. c:macro:: Py_mod_create
|
||||
|
||||
.. c:macro:: Py_mod_name
|
||||
Specifies a function that is called to create the module object itself.
|
||||
The *value* pointer of this slot must point to a function of the signature:
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for the name of the new module,
|
||||
as a NUL-terminated UTF8-encoded ``const char *``.
|
||||
.. c:function:: PyObject* create_module(PyObject *spec, PyModuleDef *def)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
|
||||
Note that modules are typically created using a
|
||||
:py:class:`~importlib.machinery.ModuleSpec`, and when they are, the
|
||||
name from the spec will be used instead of :c:data:`!Py_mod_name`.
|
||||
However, it is still recommended to include this slot for introspection
|
||||
and debugging purposes.
|
||||
The function receives a :py:class:`~importlib.machinery.ModuleSpec`
|
||||
instance, as defined in :PEP:`451`, and the module definition.
|
||||
It should return a new module object, or set an error
|
||||
and return ``NULL``.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
This function should be kept minimal. In particular, it should not
|
||||
call arbitrary Python code, as trying to import the same module again may
|
||||
result in an infinite loop.
|
||||
|
||||
Use :c:member:`PyModuleDef.m_name` instead to support previous versions.
|
||||
Multiple ``Py_mod_create`` slots may not be specified in one module
|
||||
definition.
|
||||
|
||||
.. c:macro:: Py_mod_doc
|
||||
If ``Py_mod_create`` is not specified, the import machinery will create
|
||||
a normal module object using :c:func:`PyModule_New`. The name is taken from
|
||||
*spec*, not the definition, to allow extension modules to dynamically adjust
|
||||
to their place in the module hierarchy and be imported under different
|
||||
names through symlinks, all while sharing a single module definition.
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for the docstring of the new
|
||||
module, as a NUL-terminated UTF8-encoded ``const char *``.
|
||||
There is no requirement for the returned object to be an instance of
|
||||
:c:type:`PyModule_Type`. Any type can be used, as long as it supports
|
||||
setting and getting import-related attributes.
|
||||
However, only ``PyModule_Type`` instances may be returned if the
|
||||
``PyModuleDef`` has non-``NULL`` ``m_traverse``, ``m_clear``,
|
||||
``m_free``; non-zero ``m_size``; or slots other than ``Py_mod_create``.
|
||||
|
||||
Usually it is set to a variable created with :c:macro:`PyDoc_STRVAR`.
|
||||
.. c:macro:: Py_mod_exec
|
||||
|
||||
.. versionadded:: 3.15
|
||||
Specifies a function that is called to *execute* the module.
|
||||
This is equivalent to executing the code of a Python module: typically,
|
||||
this function adds classes and constants to the module.
|
||||
The signature of the function is:
|
||||
|
||||
Use :c:member:`PyModuleDef.m_doc` instead to support previous versions.
|
||||
.. c:function:: int exec_module(PyObject* module)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
|
||||
|
||||
Feature slots
|
||||
.............
|
||||
|
||||
.. c:macro:: Py_mod_abi
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` whose value points to
|
||||
a :c:struct:`PyABIInfo` structure describing the ABI that
|
||||
the extension is using.
|
||||
|
||||
A suitable :c:struct:`!PyABIInfo` variable can be defined using the
|
||||
:c:macro:`PyABIInfo_VAR` macro, as in:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
PyABIInfo_VAR(abi_info);
|
||||
|
||||
static PyModuleDef_Slot mymodule_slots[] = {
|
||||
{Py_mod_abi, &abi_info},
|
||||
...
|
||||
};
|
||||
|
||||
When creating a module, Python checks the value of this slot
|
||||
using :c:func:`PyABIInfo_Check`.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
If multiple ``Py_mod_exec`` slots are specified, they are processed in the
|
||||
order they appear in the *m_slots* array.
|
||||
|
||||
.. c:macro:: Py_mod_multiple_interpreters
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` whose value is one of:
|
||||
Specifies one of the following values:
|
||||
|
||||
.. c:namespace:: NULL
|
||||
|
||||
|
|
@ -257,6 +353,9 @@ Feature slots
|
|||
This slot determines whether or not importing this module
|
||||
in a subinterpreter will fail.
|
||||
|
||||
Multiple ``Py_mod_multiple_interpreters`` slots may not be specified
|
||||
in one module definition.
|
||||
|
||||
If ``Py_mod_multiple_interpreters`` is not specified, the import
|
||||
machinery defaults to ``Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED``.
|
||||
|
||||
|
|
@ -264,7 +363,7 @@ Feature slots
|
|||
|
||||
.. c:macro:: Py_mod_gil
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` whose value is one of:
|
||||
Specifies one of the following values:
|
||||
|
||||
.. c:namespace:: NULL
|
||||
|
||||
|
|
@ -282,482 +381,45 @@ Feature slots
|
|||
this module will cause the GIL to be automatically enabled. See
|
||||
:ref:`whatsnew313-free-threaded-cpython` for more detail.
|
||||
|
||||
Multiple ``Py_mod_gil`` slots may not be specified in one module definition.
|
||||
|
||||
If ``Py_mod_gil`` is not specified, the import machinery defaults to
|
||||
``Py_MOD_GIL_USED``.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. c:macro:: Py_mod_abi
|
||||
|
||||
Creation and initialization slots
|
||||
.................................
|
||||
A pointer to a :c:struct:`PyABIInfo` structure that describes the ABI that
|
||||
the extension is using.
|
||||
|
||||
.. c:macro:: Py_mod_create
|
||||
When the module is loaded, the :c:struct:`!PyABIInfo` in this slot is checked
|
||||
using :c:func:`PyABIInfo_Check`.
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for a function that creates
|
||||
the module object itself.
|
||||
The function must have the signature:
|
||||
A suitable :c:struct:`!PyABIInfo` variable can be defined using the
|
||||
:c:macro:`PyABIInfo_VAR` macro, as in:
|
||||
|
||||
.. c:function:: PyObject* create_module(PyObject *spec, PyModuleDef *def)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
.. code-block:: c
|
||||
|
||||
The function will be called with:
|
||||
PyABIInfo_VAR(abi_info);
|
||||
|
||||
- *spec*: a ``ModuleSpec``-like object, meaning that any attributes defined
|
||||
for :py:class:`importlib.machinery.ModuleSpec` have matching semantics.
|
||||
However, any of the attributes may be missing.
|
||||
- *def*: ``NULL``, or the module definition if the module is created from one.
|
||||
|
||||
The function should return a new module object, or set an error
|
||||
and return ``NULL``.
|
||||
|
||||
This function should be kept minimal. In particular, it should not
|
||||
call arbitrary Python code, as trying to import the same module again may
|
||||
result in an infinite loop.
|
||||
|
||||
If ``Py_mod_create`` is not specified, the import machinery will create
|
||||
a normal module object using :c:func:`PyModule_New`. The name is taken from
|
||||
*spec*, not the definition, to allow extension modules to dynamically adjust
|
||||
to their place in the module hierarchy and be imported under different
|
||||
names through symlinks, all while sharing a single module definition.
|
||||
|
||||
There is no requirement for the returned object to be an instance of
|
||||
:c:type:`PyModule_Type`.
|
||||
However, some slots may only be used with
|
||||
:c:type:`!PyModule_Type` instances; in particular:
|
||||
|
||||
- :c:macro:`Py_mod_exec`,
|
||||
- :ref:`module state slots <ext-module-state-slots>` (``Py_mod_state_*``),
|
||||
- :c:macro:`Py_mod_token`.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
|
||||
The *slots* argument may be a ``ModuleSpec``-like object, rather than
|
||||
a true :py:class:`~importlib.machinery.ModuleSpec` instance.
|
||||
Note that previous versions of CPython did not enforce this.
|
||||
|
||||
The *def* argument may now be ``NULL``, since modules are not necessarily
|
||||
made from definitions.
|
||||
|
||||
.. c:macro:: Py_mod_exec
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for a function that will
|
||||
:dfn:`execute`, or initialize, the module.
|
||||
This function does the equivalent to executing the code of a Python module:
|
||||
typically, it adds classes and constants to the module.
|
||||
The signature of the function is:
|
||||
|
||||
.. c:function:: int exec_module(PyObject* module)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
|
||||
See the :ref:`capi-module-support-functions` section for some useful
|
||||
functions to call.
|
||||
|
||||
For backwards compatibility, the :c:type:`PyModuleDef.m_slots` array may
|
||||
contain multiple :c:macro:`!Py_mod_exec` slots; these are processed in the
|
||||
order they appear in the array.
|
||||
Elsewhere (that is, in arguments to :c:func:`PyModule_FromSlotsAndSpec`
|
||||
and in return values of :samp:`PyModExport_{<name>}`), repeating the slot
|
||||
is not allowed.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
|
||||
Repeated ``Py_mod_exec`` slots are disallowed, except in
|
||||
:c:type:`PyModuleDef.m_slots`.
|
||||
|
||||
.. c:macro:: Py_mod_methods
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for a table of module-level
|
||||
functions, as an array of :c:type:`PyMethodDef` values suitable as the
|
||||
*functions* argument to :c:func:`PyModule_AddFunctions`.
|
||||
|
||||
Like other slot IDs, a slots array may only contain one
|
||||
:c:macro:`!Py_mod_methods` entry.
|
||||
To add functions from multiple :c:type:`PyMethodDef` arrays, call
|
||||
:c:func:`PyModule_AddFunctions` in the :c:macro:`Py_mod_exec` function.
|
||||
|
||||
The table must be statically allocated (or otherwise guaranteed to outlive
|
||||
the module object).
|
||||
static PyModuleDef_Slot mymodule_slots[] = {
|
||||
{Py_mod_abi, &abi_info},
|
||||
...
|
||||
};
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
Use :c:member:`PyModuleDef.m_methods` instead to support previous versions.
|
||||
|
||||
.. _ext-module-state:
|
||||
|
||||
Module state
|
||||
------------
|
||||
|
||||
Extension modules can have *module state* -- a
|
||||
piece of memory that is allocated on module creation,
|
||||
and freed when the module object is deallocated.
|
||||
The module state is specified using :ref:`dedicated slots <ext-module-state-slots>`.
|
||||
|
||||
A typical use of module state is storing an exception type -- or indeed *any*
|
||||
type object defined by the module --
|
||||
|
||||
Unlike the module's Python attributes, Python code cannot replace or delete
|
||||
data stored in module state.
|
||||
|
||||
Keeping per-module information in attributes and module state, rather than in
|
||||
static globals, makes module objects *isolated* and safer for use in
|
||||
multiple sub-interpreters.
|
||||
It also helps Python do an orderly clean-up when it shuts down.
|
||||
|
||||
Extensions that keep references to Python objects as part of module state must
|
||||
implement :c:macro:`Py_mod_state_traverse` and :c:macro:`Py_mod_state_clear`
|
||||
functions to avoid reference leaks.
|
||||
|
||||
To retrieve the state from a given module, use the following functions:
|
||||
|
||||
.. c:function:: void* PyModule_GetState(PyObject *module)
|
||||
|
||||
Return the "state" of the module, that is, a pointer to the block of memory
|
||||
allocated at module creation time, or ``NULL``. See
|
||||
:c:macro:`Py_mod_state_size`.
|
||||
|
||||
On error, return ``NULL`` with an exception set.
|
||||
Use :c:func:`PyErr_Occurred` to tell this case apart from missing
|
||||
module state.
|
||||
|
||||
|
||||
.. c:function:: int PyModule_GetStateSize(PyObject *, Py_ssize_t *result)
|
||||
|
||||
Set *\*result* to the size of the module's state, as specified using
|
||||
:c:macro:`Py_mod_state_size` (or :c:member:`PyModuleDef.m_size`),
|
||||
and return 0.
|
||||
|
||||
On error, set *\*result* to -1, and return -1 with an exception set.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
|
||||
|
||||
.. _ext-module-state-slots:
|
||||
|
||||
Slots for defining module state
|
||||
...............................
|
||||
|
||||
The following :c:member:`PyModuleDef_Slot.slot` IDs are available for
|
||||
defining the module state.
|
||||
|
||||
.. c:macro:: Py_mod_state_size
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for the size of the module state,
|
||||
in bytes.
|
||||
|
||||
Setting the value to a non-negative value means that the module can be
|
||||
re-initialized and specifies the additional amount of memory it requires
|
||||
for its state.
|
||||
|
||||
See :PEP:`3121` for more details.
|
||||
|
||||
Use :c:func:`PyModule_GetStateSize` to retrieve the size of a given module.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
Use :c:member:`PyModuleDef.m_size` instead to support previous versions.
|
||||
|
||||
.. c:macro:: Py_mod_state_traverse
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for a traversal function to call
|
||||
during GC traversal of the module object.
|
||||
|
||||
The signature of the function, and meanings of the arguments,
|
||||
is similar as for :c:member:`PyTypeObject.tp_traverse`:
|
||||
|
||||
.. c:function:: int traverse_module_state(PyObject *module, visitproc visit, void *arg)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
|
||||
This function is not called if the module state was requested but is not
|
||||
allocated yet. This is the case immediately after the module is created
|
||||
and before the module is executed (:c:data:`Py_mod_exec` function). More
|
||||
precisely, this function is not called if the state size
|
||||
(:c:data:`Py_mod_state_size`) is greater than 0 and the module state
|
||||
(as returned by :c:func:`PyModule_GetState`) is ``NULL``.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
Use :c:member:`PyModuleDef.m_size` instead to support previous versions.
|
||||
|
||||
.. c:macro:: Py_mod_state_clear
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for a clear function to call
|
||||
during GC clearing of the module object.
|
||||
|
||||
The signature of the function is:
|
||||
|
||||
.. c:function:: int clear_module_state(PyObject* module)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
|
||||
This function is not called if the module state was requested but is not
|
||||
allocated yet. This is the case immediately after the module is created
|
||||
and before the module is executed (:c:data:`Py_mod_exec` function). More
|
||||
precisely, this function is not called if the state size
|
||||
(:c:data:`Py_mod_state_size`) is greater than 0 and the module state
|
||||
(as returned by :c:func:`PyModule_GetState`) is ``NULL``.
|
||||
|
||||
Like :c:member:`PyTypeObject.tp_clear`, this function is not *always*
|
||||
called before a module is deallocated. For example, when reference
|
||||
counting is enough to determine that an object is no longer used,
|
||||
the cyclic garbage collector is not involved and
|
||||
the :c:macro:`Py_mod_state_free` function is called directly.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
Use :c:member:`PyModuleDef.m_clear` instead to support previous versions.
|
||||
|
||||
.. c:macro:: Py_mod_state_free
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for a function to call during
|
||||
deallocation of the module object.
|
||||
|
||||
The signature of the function is:
|
||||
|
||||
.. c:function:: int free_module_state(PyObject* module)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
|
||||
This function is not called if the module state was requested but is not
|
||||
allocated yet. This is the case immediately after the module is created
|
||||
and before the module is executed (:c:data:`Py_mod_exec` function). More
|
||||
precisely, this function is not called if the state size
|
||||
(:c:data:`Py_mod_state_size`) is greater than 0 and the module state
|
||||
(as returned by :c:func:`PyModule_GetState`) is ``NULL``.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
Use :c:member:`PyModuleDef.m_free` instead to support previous versions.
|
||||
|
||||
|
||||
.. _ext-module-token:
|
||||
|
||||
Module token
|
||||
............
|
||||
|
||||
Each module may have an associated *token*: a pointer-sized value intended to
|
||||
identify of the module state's memory layout.
|
||||
This means that if you have a module object, but you are not sure if it
|
||||
“belongs” to your extension, you can check using code like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
PyObject *module = <the module in question>
|
||||
|
||||
void *module_token;
|
||||
if (PyModule_GetToken(module, &module_token) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (module_token != your_token) {
|
||||
PyErr_SetString(PyExc_ValueError, "unexpected module")
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// This module's state has the expected memory layout; it's safe to cast
|
||||
struct my_state state = (struct my_state*)PyModule_GetState(module)
|
||||
|
||||
A module's token -- and the *your_token* value to use in the above code -- is:
|
||||
|
||||
- For modules created with :c:type:`PyModuleDef`: the address of that
|
||||
:c:type:`PyModuleDef`;
|
||||
- For modules defined with the :c:macro:`Py_mod_token` slot: the value
|
||||
of that slot;
|
||||
- For modules created from an ``PyModExport_*``
|
||||
:ref:`export hook <extension-export-hook>`: the slots array that the export
|
||||
hook returned (unless overriden with :c:macro:`Py_mod_token`).
|
||||
|
||||
.. c:macro:: Py_mod_token
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for the module token.
|
||||
|
||||
If you use this slot to set the module token (rather than rely on the
|
||||
default), you must ensure that:
|
||||
|
||||
* The pointer outlives the class, so it's not reused for something else
|
||||
while the class exists.
|
||||
* It "belongs" to the extension module where the class lives, so it will not
|
||||
clash with other extensions.
|
||||
* If the token points to a :c:type:`PyModuleDef` struct, the module should
|
||||
behave as if it was created from that :c:type:`PyModuleDef`.
|
||||
In particular, the module state must have matching layout and semantics.
|
||||
|
||||
Modules created from :c:type:`PyModuleDef` always use the address of
|
||||
the :c:type:`PyModuleDef` as the token.
|
||||
This means that :c:macro:`!Py_mod_token` cannot be used in
|
||||
:c:member:`PyModuleDef.m_slots`.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
.. c:function:: int PyModule_GetToken(PyObject *module, void** result)
|
||||
|
||||
Set *\*result* to the module's token and return 0.
|
||||
|
||||
On error, set *\*result* to NULL, and return -1 with an exception set.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
See also :c:func:`PyType_GetModuleByToken`.
|
||||
|
||||
|
||||
.. _module-from-slots:
|
||||
|
||||
Creating extension modules dynamically
|
||||
--------------------------------------
|
||||
|
||||
The following functions may be used to create an extension module dynamically,
|
||||
rather than from an extension's :ref:`export hook <extension-export-hook>`.
|
||||
|
||||
.. c:function:: PyObject *PyModule_FromSlotsAndSpec(const PyModuleDef_Slot *slots, PyObject *spec)
|
||||
|
||||
Create a new module object, given an array of :ref:`slots <pymoduledef_slot>`
|
||||
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
|
||||
(typically written as ``{0}`` or ``{0, NULL}`` in C).
|
||||
The *slots* argument may not be ``NULL``.
|
||||
|
||||
The *spec* argument may be any ``ModuleSpec``-like object, as described
|
||||
in :c:macro:`Py_mod_create` documentation.
|
||||
Currently, the *spec* must have a ``name`` attribute.
|
||||
|
||||
On success, return the new module.
|
||||
On error, return ``NULL`` with an exception set.
|
||||
|
||||
Note that this does not process the module's execution slot
|
||||
(:c:data:`Py_mod_exec`).
|
||||
Both :c:func:`!PyModule_FromSlotsAndSpec` and :c:func:`PyModule_Exec`
|
||||
must be called to fully initialize a module.
|
||||
(See also :ref:`multi-phase-initialization`.)
|
||||
|
||||
The *slots* array only needs to be valid for the duration of the
|
||||
:c:func:`!PyModule_FromSlotsAndSpec` call.
|
||||
In particular, it may be heap-allocated.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
.. c:function:: int PyModule_Exec(PyObject *module)
|
||||
|
||||
Execute the :c:data:`Py_mod_exec` slot(s) of the given *module*.
|
||||
|
||||
On success, return 0.
|
||||
On error, return -1 with an exception set.
|
||||
|
||||
For clarity: If *module* has no slots, for example if it uses
|
||||
:ref:`legacy single-phase initialization <single-phase-initialization>`,
|
||||
this function does nothing and returns 0.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
|
||||
|
||||
.. _pymoduledef:
|
||||
|
||||
Module definition struct
|
||||
------------------------
|
||||
|
||||
Traditionally, extension modules were defined using a *module definition*
|
||||
as the “description" of how a module should be created.
|
||||
Rather than using an array of :ref:`slots <pymoduledef_slot>` directly,
|
||||
the definition has dedicated members for most common functionality,
|
||||
and allows additional slots as an extension mechanism.
|
||||
|
||||
This way of defining modules is still available and there are no plans to
|
||||
remove it.
|
||||
|
||||
.. c:type:: PyModuleDef
|
||||
|
||||
The module definition struct, which holds information needed to create
|
||||
a module object.
|
||||
|
||||
This structure must be statically allocated (or be otherwise guaranteed
|
||||
to be valid while any modules created from it exist).
|
||||
Usually, there is only one variable of this type for each extension module
|
||||
defined this way.
|
||||
|
||||
.. c:member:: PyModuleDef_Base m_base
|
||||
|
||||
Always initialize this member to :c:macro:`PyModuleDef_HEAD_INIT`:
|
||||
|
||||
.. c:namespace:: NULL
|
||||
|
||||
.. c:type:: PyModuleDef_Base
|
||||
|
||||
The type of :c:member:`!PyModuleDef.m_base`.
|
||||
|
||||
.. c:macro:: PyModuleDef_HEAD_INIT
|
||||
|
||||
The required initial value for :c:member:`!PyModuleDef.m_base`.
|
||||
|
||||
.. c:member:: const char *m_name
|
||||
|
||||
Corresponds to the :c:macro:`Py_mod_name` slot.
|
||||
|
||||
.. c:member:: const char *m_doc
|
||||
|
||||
These members correspond to the :c:macro:`Py_mod_doc` slot.
|
||||
Setting this to NULL is equivalent to omitting the slot.
|
||||
|
||||
.. c:member:: Py_ssize_t m_size
|
||||
|
||||
Corresponds to the :c:macro:`Py_mod_state_size` slot.
|
||||
Setting this to zero is equivalent to omitting the slot.
|
||||
|
||||
When using :ref:`legacy single-phase initialization <single-phase-initialization>`
|
||||
or when creating modules dynamically using :c:func:`PyModule_Create`
|
||||
or :c:func:`PyModule_Create2`, :c:member:`!m_size` may be set to -1.
|
||||
This indicates that the module does not support sub-interpreters,
|
||||
because it has global state.
|
||||
|
||||
.. c:member:: PyMethodDef *m_methods
|
||||
|
||||
Corresponds to the :c:macro:`Py_mod_methods` slot.
|
||||
Setting this to NULL is equivalent to omitting the slot.
|
||||
|
||||
.. c:member:: PyModuleDef_Slot* m_slots
|
||||
|
||||
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`.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
Prior to version 3.5, this member was always set to ``NULL``,
|
||||
and was defined as:
|
||||
|
||||
.. c:member:: inquiry m_reload
|
||||
|
||||
.. c:member:: traverseproc m_traverse
|
||||
inquiry m_clear
|
||||
freefunc m_free
|
||||
|
||||
These members correspond to the :c:macro:`Py_mod_state_traverse`,
|
||||
:c:macro:`Py_mod_state_clear`, and :c:macro:`Py_mod_state_free` slots,
|
||||
respectively.
|
||||
|
||||
Setting these members to NULL is equivalent to omitting the
|
||||
corresponding slots.
|
||||
|
||||
.. 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.
|
||||
|
||||
|
||||
.. _moduledef-dynamic:
|
||||
|
||||
The following API can be used to create modules from a :c:type:`!PyModuleDef`
|
||||
struct:
|
||||
Creating extension modules dynamically
|
||||
--------------------------------------
|
||||
|
||||
The following functions may be used to create a module outside of an
|
||||
extension's :ref:`initialization function <extension-export-hook>`.
|
||||
They are also used in
|
||||
:ref:`single-phase initialization <single-phase-initialization>`.
|
||||
|
||||
.. c:function:: PyObject* PyModule_Create(PyModuleDef *def)
|
||||
|
||||
|
|
@ -834,13 +496,12 @@ struct:
|
|||
useful for versioning. This may change in the future.
|
||||
|
||||
|
||||
.. _capi-module-support-functions:
|
||||
|
||||
Support functions
|
||||
-----------------
|
||||
|
||||
The following functions are provided to help initialize a module object.
|
||||
They are intended for a module's execution slot (:c:data:`Py_mod_exec`),
|
||||
The following functions are provided to help initialize a module
|
||||
state.
|
||||
They are intended for a module's execution slots (:c:data:`Py_mod_exec`),
|
||||
the initialization function for legacy :ref:`single-phase initialization <single-phase-initialization>`,
|
||||
or code that creates modules dynamically.
|
||||
|
||||
|
|
@ -1006,9 +667,6 @@ or code that creates modules dynamically.
|
|||
:c:type:`PyMethodDef` arrays; in that case they should call this function
|
||||
directly.
|
||||
|
||||
The *functions* array must be statically allocated (or otherwise guaranteed
|
||||
to outlive the module object).
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
.. c:function:: int PyModule_SetDocString(PyObject *module, const char *docstring)
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ Managing the Monitoring State
|
|||
-----------------------------
|
||||
|
||||
Monitoring states can be managed with the help of monitoring scopes. A scope
|
||||
would typically correspond to a Python function.
|
||||
would typically correspond to a python function.
|
||||
|
||||
.. c:function:: int PyMonitoring_EnterScope(PyMonitoringState *state_array, uint64_t *version, const uint8_t *event_types, Py_ssize_t length)
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ Object Protocol
|
|||
|
||||
Flag to be used with multiple functions that print the object (like
|
||||
:c:func:`PyObject_Print` and :c:func:`PyFile_WriteObject`).
|
||||
If passed, these functions use the :func:`str` of the object
|
||||
If passed, these function would use the :func:`str` of the object
|
||||
instead of the :func:`repr`.
|
||||
|
||||
|
||||
|
|
@ -85,35 +85,6 @@ Object Protocol
|
|||
instead of the :func:`repr`.
|
||||
|
||||
|
||||
.. c:function:: void PyUnstable_Object_Dump(PyObject *op)
|
||||
|
||||
Dump an object *op* to ``stderr``. This should only be used for debugging.
|
||||
|
||||
The output is intended to try dumping objects even after memory corruption:
|
||||
|
||||
* Information is written starting with fields that are the least likely to
|
||||
crash when accessed.
|
||||
* This function can be called without an :term:`attached thread state`, but
|
||||
it's not recommended to do so: it can cause deadlocks.
|
||||
* An object that does not belong to the current interpreter may be dumped,
|
||||
but this may also cause crashes or unintended behavior.
|
||||
* Implement a heuristic to detect if the object memory has been freed. Don't
|
||||
display the object contents in this case, only its memory address.
|
||||
* The output format may change at any time.
|
||||
|
||||
Example of output:
|
||||
|
||||
.. code-block:: output
|
||||
|
||||
object address : 0x7f80124702c0
|
||||
object refcount : 2
|
||||
object type : 0x9902e0
|
||||
object type name: str
|
||||
object repr : 'abcdef'
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
|
||||
.. c:function:: int PyObject_HasAttrWithError(PyObject *o, PyObject *attr_name)
|
||||
|
||||
Returns ``1`` if *o* has the attribute *attr_name*, and ``0`` otherwise.
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
.. highlight:: c
|
||||
|
||||
.. _picklebuffer-objects:
|
||||
|
||||
.. index::
|
||||
pair: object; PickleBuffer
|
||||
|
||||
Pickle buffer objects
|
||||
---------------------
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
A :class:`pickle.PickleBuffer` object wraps a :ref:`buffer-providing object
|
||||
<bufferobjects>` for out-of-band data transfer with the :mod:`pickle` module.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyPickleBuffer_Type
|
||||
|
||||
This instance of :c:type:`PyTypeObject` represents the Python pickle buffer type.
|
||||
This is the same object as :class:`pickle.PickleBuffer` in the Python layer.
|
||||
|
||||
|
||||
.. c:function:: int PyPickleBuffer_Check(PyObject *op)
|
||||
|
||||
Return true if *op* is a pickle buffer instance.
|
||||
This function always succeeds.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyPickleBuffer_FromObject(PyObject *obj)
|
||||
|
||||
Create a pickle buffer from the object *obj*.
|
||||
|
||||
This function will fail if *obj* doesn't support the :ref:`buffer protocol <bufferobjects>`.
|
||||
|
||||
On success, return a new pickle buffer instance.
|
||||
On failure, set an exception and return ``NULL``.
|
||||
|
||||
Analogous to calling :class:`pickle.PickleBuffer` with *obj* in Python.
|
||||
|
||||
|
||||
.. c:function:: const Py_buffer *PyPickleBuffer_GetBuffer(PyObject *picklebuf)
|
||||
|
||||
Get a pointer to the underlying :c:type:`Py_buffer` that the pickle buffer wraps.
|
||||
|
||||
The returned pointer is valid as long as *picklebuf* is alive and has not been
|
||||
released. The caller must not modify or free the returned :c:type:`Py_buffer`.
|
||||
If the pickle buffer has been released, raise :exc:`ValueError`.
|
||||
|
||||
On success, return a pointer to the buffer view.
|
||||
On failure, set an exception and return ``NULL``.
|
||||
|
||||
|
||||
.. c:function:: int PyPickleBuffer_Release(PyObject *picklebuf)
|
||||
|
||||
Release the underlying buffer held by the pickle buffer.
|
||||
|
||||
Return ``0`` on success. On failure, set an exception and return ``-1``.
|
||||
|
||||
Analogous to calling :meth:`pickle.PickleBuffer.release` in Python.
|
||||
|
|
@ -147,7 +147,7 @@ subtypes but not for instances of :class:`frozenset` or its subtypes.
|
|||
|
||||
Return ``1`` if found and removed, ``0`` if not found (no action taken), and ``-1`` if an
|
||||
error is encountered. Does not raise :exc:`KeyError` for missing keys. Raise a
|
||||
:exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~set.discard`
|
||||
:exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~frozenset.discard`
|
||||
method, this function does not automatically convert unhashable sets into
|
||||
temporary frozensets. Raise :exc:`SystemError` if *set* is not an
|
||||
instance of :class:`set` or its subtype.
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ The full API is described below for advanced use cases.
|
|||
|
||||
.. c:member:: uint8_t abiinfo_minor_version
|
||||
|
||||
The minor version of :c:struct:`PyABIInfo`.
|
||||
The major version of :c:struct:`PyABIInfo`.
|
||||
Must be set to ``0``; larger values are reserved for backwards-compatible
|
||||
future versions of :c:struct:`!PyABIInfo`.
|
||||
|
||||
|
|
@ -294,7 +294,7 @@ The full API is described below for advanced use cases.
|
|||
Default flags, based on current values of macros such as
|
||||
:c:macro:`Py_LIMITED_API` and :c:macro:`Py_GIL_DISABLED`.
|
||||
|
||||
Alternately, the field can be set to the following flags, combined
|
||||
Alternately, the field can be set to to the following flags, combined
|
||||
by bitwise OR.
|
||||
Unused bits must be set to zero.
|
||||
|
||||
|
|
|
|||
|
|
@ -280,8 +280,6 @@ Implementing functions and methods
|
|||
|
||||
Name of the method.
|
||||
|
||||
A ``NULL`` *ml_name* marks the end of a :c:type:`!PyMethodDef` array.
|
||||
|
||||
.. c:member:: PyCFunction ml_meth
|
||||
|
||||
Pointer to the C implementation.
|
||||
|
|
@ -449,25 +447,6 @@ definition with the same method name.
|
|||
slot. This is helpful because calls to PyCFunctions are optimized more
|
||||
than wrapper object calls.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyCMethod_Type
|
||||
|
||||
The type object corresponding to Python C method objects. This is
|
||||
available as :class:`types.BuiltinMethodType` in the Python layer.
|
||||
|
||||
|
||||
.. c:function:: int PyCMethod_Check(PyObject *op)
|
||||
|
||||
Return true if *op* is an instance of the :c:type:`PyCMethod_Type` type
|
||||
or a subtype of it. This function always succeeds.
|
||||
|
||||
|
||||
.. c:function:: int PyCMethod_CheckExact(PyObject *op)
|
||||
|
||||
This is the same as :c:func:`PyCMethod_Check`, but does not account for
|
||||
subtypes.
|
||||
|
||||
|
||||
.. c:function:: PyObject * PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *cls)
|
||||
|
||||
Turn *ml* into a Python :term:`callable` object.
|
||||
|
|
@ -493,24 +472,6 @@ definition with the same method name.
|
|||
.. versionadded:: 3.9
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyCFunction_Type
|
||||
|
||||
The type object corresponding to Python C function objects. This is
|
||||
available as :class:`types.BuiltinFunctionType` in the Python layer.
|
||||
|
||||
|
||||
.. c:function:: int PyCFunction_Check(PyObject *op)
|
||||
|
||||
Return true if *op* is an instance of the :c:type:`PyCFunction_Type` type
|
||||
or a subtype of it. This function always succeeds.
|
||||
|
||||
|
||||
.. c:function:: int PyCFunction_CheckExact(PyObject *op)
|
||||
|
||||
This is the same as :c:func:`PyCFunction_Check`, but does not account for
|
||||
subtypes.
|
||||
|
||||
|
||||
.. c:function:: PyObject * PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
|
||||
|
||||
Equivalent to ``PyCMethod_New(ml, self, module, NULL)``.
|
||||
|
|
@ -521,62 +482,6 @@ definition with the same method name.
|
|||
Equivalent to ``PyCMethod_New(ml, self, NULL, NULL)``.
|
||||
|
||||
|
||||
.. c:function:: int PyCFunction_GetFlags(PyObject *func)
|
||||
|
||||
Get the function's flags on *func* as they were passed to
|
||||
:c:member:`~PyMethodDef.ml_flags`.
|
||||
|
||||
If *func* is not a C function object, this fails with an exception.
|
||||
*func* must not be ``NULL``.
|
||||
|
||||
This function returns the function's flags on success, and ``-1`` with an
|
||||
exception set on failure.
|
||||
|
||||
|
||||
.. c:function:: int PyCFunction_GET_FLAGS(PyObject *func)
|
||||
|
||||
This is the same as :c:func:`PyCFunction_GetFlags`, but without error
|
||||
or type checking.
|
||||
|
||||
|
||||
.. c:function:: PyCFunction PyCFunction_GetFunction(PyObject *func)
|
||||
|
||||
Get the function pointer on *func* as it was passed to
|
||||
:c:member:`~PyMethodDef.ml_meth`.
|
||||
|
||||
If *func* is not a C function object, this fails with an exception.
|
||||
*func* must not be ``NULL``.
|
||||
|
||||
This function returns the function pointer on success, and ``NULL`` with an
|
||||
exception set on failure.
|
||||
|
||||
|
||||
.. c:function:: int PyCFunction_GET_FUNCTION(PyObject *func)
|
||||
|
||||
This is the same as :c:func:`PyCFunction_GetFunction`, but without error
|
||||
or type checking.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyCFunction_GetSelf(PyObject *func)
|
||||
|
||||
Get the "self" object on *func*. This is the object that would be passed
|
||||
to the first argument of a :c:type:`PyCFunction`. For C function objects
|
||||
created through a :c:type:`PyMethodDef` on a :c:type:`PyModuleDef`, this
|
||||
is the resulting module object.
|
||||
|
||||
If *func* is not a C function object, this fails with an exception.
|
||||
*func* must not be ``NULL``.
|
||||
|
||||
This function returns a :term:`borrowed reference` to the "self" object
|
||||
on success, and ``NULL`` with an exception set on failure.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyCFunction_GET_SELF(PyObject *func)
|
||||
|
||||
This is the same as :c:func:`PyCFunction_GetSelf`, but without error or
|
||||
type checking.
|
||||
|
||||
|
||||
Accessing attributes of extension types
|
||||
---------------------------------------
|
||||
|
||||
|
|
@ -700,12 +605,14 @@ The following flags can be used with :c:member:`PyMemberDef.flags`:
|
|||
entry indicates an offset from the subclass-specific data, rather than
|
||||
from ``PyObject``.
|
||||
|
||||
Can only be used as part of the :c:data:`Py_tp_members`
|
||||
Can only be used as part of :c:member:`Py_tp_members <PyTypeObject.tp_members>`
|
||||
:c:type:`slot <PyType_Slot>` when creating a class using negative
|
||||
:c:member:`~PyType_Spec.basicsize`.
|
||||
It is mandatory in that case.
|
||||
When setting :c:member:`~PyTypeObject.tp_members` from the slot during
|
||||
class creation, Python clears the flag and sets
|
||||
|
||||
This flag is only used in :c:type:`PyType_Slot`.
|
||||
When setting :c:member:`~PyTypeObject.tp_members` during
|
||||
class creation, Python clears it and sets
|
||||
:c:member:`PyMemberDef.offset` to the offset from the ``PyObject`` struct.
|
||||
|
||||
.. index::
|
||||
|
|
|
|||
|
|
@ -123,24 +123,6 @@ Operating System Utilities
|
|||
This is a thin wrapper around either :c:func:`!sigaction` or :c:func:`!signal`. Do
|
||||
not call those functions directly!
|
||||
|
||||
|
||||
.. c:function:: int PyOS_InterruptOccurred(void)
|
||||
|
||||
Check if a :c:macro:`!SIGINT` signal has been received.
|
||||
|
||||
Returns ``1`` if a :c:macro:`!SIGINT` has occurred and clears the signal flag,
|
||||
or ``0`` otherwise.
|
||||
|
||||
In most cases, you should prefer :c:func:`PyErr_CheckSignals` over this function.
|
||||
:c:func:`!PyErr_CheckSignals` invokes the appropriate signal handlers
|
||||
for all pending signals, allowing Python code to handle the signal properly.
|
||||
This function only detects :c:macro:`!SIGINT` and does not invoke any Python
|
||||
signal handlers.
|
||||
|
||||
This function is async-signal-safe and this function cannot fail.
|
||||
The caller must hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:function:: wchar_t* Py_DecodeLocale(const char* arg, size_t *size)
|
||||
|
||||
.. warning::
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ Tuple Objects
|
|||
.. c:function:: Py_ssize_t PyTuple_Size(PyObject *p)
|
||||
|
||||
Take a pointer to a tuple object, and return the size of that tuple.
|
||||
On error, return ``-1`` with an exception set.
|
||||
On error, return ``-1`` and with an exception set.
|
||||
|
||||
|
||||
.. c:function:: Py_ssize_t PyTuple_GET_SIZE(PyObject *p)
|
||||
|
|
@ -148,11 +148,8 @@ Tuple Objects
|
|||
Struct Sequence Objects
|
||||
-----------------------
|
||||
|
||||
A struct sequence object is a :term:`named tuple`, that is, a sequence
|
||||
whose items can also be accessed through attributes.
|
||||
It is similar to :func:`collections.namedtuple`, but provides a slightly
|
||||
different interface.
|
||||
|
||||
Struct sequence objects are the C equivalent of :func:`~collections.namedtuple`
|
||||
objects, i.e. a sequence whose items can also be accessed through attributes.
|
||||
To create a struct sequence, you first have to create a specific struct sequence
|
||||
type.
|
||||
|
||||
|
|
|
|||
|
|
@ -116,20 +116,6 @@ Type Objects
|
|||
.. versionadded:: 3.12
|
||||
|
||||
|
||||
.. c:function:: int PyType_Unwatch(int watcher_id, PyObject *type)
|
||||
|
||||
Mark *type* as not watched. This undoes a previous call to
|
||||
:c:func:`PyType_Watch`. *type* must not be ``NULL``.
|
||||
|
||||
An extension should never call this function with a *watcher_id* that was
|
||||
not returned to it by a previous call to :c:func:`PyType_AddWatcher`.
|
||||
|
||||
On success, this function returns ``0``. On failure, this function returns
|
||||
``-1`` with an exception set.
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
|
||||
.. c:type:: int (*PyType_WatchCallback)(PyObject *type)
|
||||
|
||||
Type of a type-watcher callback function.
|
||||
|
|
@ -147,18 +133,6 @@ Type Objects
|
|||
Type features are denoted by single bit flags.
|
||||
|
||||
|
||||
.. c:function:: int PyType_FastSubclass(PyTypeObject *type, int flag)
|
||||
|
||||
Return non-zero if the type object *type* sets the subclass flag *flag*.
|
||||
Subclass flags are denoted by
|
||||
:c:macro:`Py_TPFLAGS_*_SUBCLASS <Py_TPFLAGS_LONG_SUBCLASS>`.
|
||||
This function is used by many ``_Check`` functions for common types.
|
||||
|
||||
.. seealso::
|
||||
:c:func:`PyObject_TypeCheck`, which is used as a slower alternative in
|
||||
``_Check`` functions for types that don't come with subclass flags.
|
||||
|
||||
|
||||
.. c:function:: int PyType_IS_GC(PyTypeObject *o)
|
||||
|
||||
Return true if the type object includes support for the cycle detector; this
|
||||
|
|
@ -195,14 +169,12 @@ Type Objects
|
|||
before initialization) and should be paired with :c:func:`PyObject_Free` in
|
||||
:c:member:`~PyTypeObject.tp_free`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
|
||||
Generic handler for the :c:member:`~PyTypeObject.tp_new` slot of a type
|
||||
object. Creates a new instance using the type's
|
||||
:c:member:`~PyTypeObject.tp_alloc` slot and returns the resulting object.
|
||||
|
||||
|
||||
.. c:function:: int PyType_Ready(PyTypeObject *type)
|
||||
|
||||
Finalize a type object. This should be called on all type objects to finish
|
||||
|
|
@ -219,7 +191,6 @@ Type Objects
|
|||
GC protocol itself by at least implementing the
|
||||
:c:member:`~PyTypeObject.tp_traverse` handle.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyType_GetName(PyTypeObject *type)
|
||||
|
||||
Return the type's name. Equivalent to getting the type's
|
||||
|
|
@ -227,7 +198,6 @@ Type Objects
|
|||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyType_GetQualName(PyTypeObject *type)
|
||||
|
||||
Return the type's qualified name. Equivalent to getting the
|
||||
|
|
@ -243,7 +213,6 @@ Type Objects
|
|||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyType_GetModuleName(PyTypeObject *type)
|
||||
|
||||
Return the type's module name. Equivalent to getting the
|
||||
|
|
@ -251,7 +220,6 @@ Type Objects
|
|||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
.. c:function:: void* PyType_GetSlot(PyTypeObject *type, int slot)
|
||||
|
||||
Return the function pointer stored in the given slot. If the
|
||||
|
|
@ -268,7 +236,6 @@ Type Objects
|
|||
:c:func:`PyType_GetSlot` can now accept all types.
|
||||
Previously, it was limited to :ref:`heap types <heap-types>`.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyType_GetModule(PyTypeObject *type)
|
||||
|
||||
Return the module object associated with the given type when the type was
|
||||
|
|
@ -283,12 +250,11 @@ Type Objects
|
|||
``Py_TYPE(self)`` may be a *subclass* of the intended class, and subclasses
|
||||
are not necessarily defined in the same module as their superclass.
|
||||
See :c:type:`PyCMethod` to get the class that defines the method.
|
||||
See :c:func:`PyType_GetModuleByToken` for cases when :c:type:`!PyCMethod`
|
||||
cannot be used.
|
||||
See :c:func:`PyType_GetModuleByDef` for cases when :c:type:`!PyCMethod` cannot
|
||||
be used.
|
||||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
|
||||
.. c:function:: void* PyType_GetModuleState(PyTypeObject *type)
|
||||
|
||||
Return the state of the module object associated with the given type.
|
||||
|
|
@ -303,11 +269,10 @@ Type Objects
|
|||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
.. c:function:: PyObject* PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
|
||||
|
||||
.. c:function:: PyObject* PyType_GetModuleByToken(PyTypeObject *type, const void *mod_token)
|
||||
|
||||
Find the first superclass whose module has the given
|
||||
:ref:`module token <ext-module-token>`, and return that module.
|
||||
Find the first superclass whose module was created from
|
||||
the given :c:type:`PyModuleDef` *def*, and return that module.
|
||||
|
||||
If no module is found, raises a :py:class:`TypeError` and returns ``NULL``.
|
||||
|
||||
|
|
@ -317,34 +282,16 @@ Type Objects
|
|||
and other places where a method's defining class cannot be passed using the
|
||||
:c:type:`PyCMethod` calling convention.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
|
||||
|
||||
Find the first superclass whose module was created from the given
|
||||
:c:type:`PyModuleDef` *def*, or whose :ref:`module token <ext-module-token>`
|
||||
is equal to *def*, and return that module.
|
||||
|
||||
Note that modules created from a :c:type:`PyModuleDef` always have their
|
||||
token set to the :c:type:`PyModuleDef`'s address.
|
||||
In other words, this function is equivalent to
|
||||
:c:func:`PyType_GetModuleByToken`, except that it:
|
||||
|
||||
- returns a borrowed reference, and
|
||||
- has a non-``void*`` argument type (which is a cosmetic difference in C).
|
||||
|
||||
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.
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
|
||||
.. c:function:: int PyType_GetBaseByToken(PyTypeObject *type, void *tp_token, PyTypeObject **result)
|
||||
.. c:function:: int PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
|
||||
|
||||
Find the first superclass in *type*'s :term:`method resolution order` whose
|
||||
:c:macro:`Py_tp_token` token is equal to *tp_token*.
|
||||
:c:macro:`Py_tp_token` token is equal to the given one.
|
||||
|
||||
* If found, set *\*result* to a new :term:`strong reference`
|
||||
to it and return ``1``.
|
||||
|
|
@ -355,11 +302,10 @@ Type Objects
|
|||
The *result* argument may be ``NULL``, in which case *\*result* is not set.
|
||||
Use this if you need only the return value.
|
||||
|
||||
The *tp_token* argument may not be ``NULL``.
|
||||
The *token* argument may not be ``NULL``.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
|
||||
.. c:function:: int PyUnstable_Type_AssignVersionTag(PyTypeObject *type)
|
||||
|
||||
Attempt to assign a version tag to the given type.
|
||||
|
|
@ -370,16 +316,6 @@ Type Objects
|
|||
.. versionadded:: 3.12
|
||||
|
||||
|
||||
.. c:function:: int PyType_SUPPORTS_WEAKREFS(PyTypeObject *type)
|
||||
|
||||
Return true if instances of *type* support creating weak references, false
|
||||
otherwise. This function always succeeds. *type* must not be ``NULL``.
|
||||
|
||||
.. seealso::
|
||||
* :ref:`weakrefobjects`
|
||||
* :py:mod:`weakref`
|
||||
|
||||
|
||||
Creating Heap-Allocated Types
|
||||
.............................
|
||||
|
||||
|
|
@ -400,8 +336,8 @@ The following functions and structs are used to create
|
|||
|
||||
The *bases* argument can be used to specify base classes; it can either
|
||||
be only one class or a tuple of classes.
|
||||
If *bases* is ``NULL``, the :c:data:`Py_tp_bases` slot is used instead.
|
||||
If that also is ``NULL``, the :c:data:`Py_tp_base` slot is used instead.
|
||||
If *bases* is ``NULL``, the *Py_tp_bases* slot is used instead.
|
||||
If that also is ``NULL``, the *Py_tp_base* slot is used instead.
|
||||
If that also is ``NULL``, the new type derives from :class:`object`.
|
||||
|
||||
The *module* argument can be used to record the module in which the new
|
||||
|
|
@ -428,7 +364,6 @@ The following functions and structs are used to create
|
|||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
|
||||
|
||||
Equivalent to ``PyType_FromMetaclass(NULL, module, spec, bases)``.
|
||||
|
|
@ -455,7 +390,6 @@ The following functions and structs are used to create
|
|||
Creating classes whose metaclass overrides
|
||||
:c:member:`~PyTypeObject.tp_new` is no longer allowed.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
|
||||
|
||||
Equivalent to ``PyType_FromMetaclass(NULL, NULL, spec, bases)``.
|
||||
|
|
@ -477,7 +411,6 @@ The following functions and structs are used to create
|
|||
Creating classes whose metaclass overrides
|
||||
:c:member:`~PyTypeObject.tp_new` is no longer allowed.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyType_FromSpec(PyType_Spec *spec)
|
||||
|
||||
Equivalent to ``PyType_FromMetaclass(NULL, NULL, spec, NULL)``.
|
||||
|
|
@ -498,7 +431,6 @@ The following functions and structs are used to create
|
|||
Creating classes whose metaclass overrides
|
||||
:c:member:`~PyTypeObject.tp_new` is no longer allowed.
|
||||
|
||||
|
||||
.. c:function:: int PyType_Freeze(PyTypeObject *type)
|
||||
|
||||
Make a type immutable: set the :c:macro:`Py_TPFLAGS_IMMUTABLETYPE` flag.
|
||||
|
|
@ -607,9 +539,9 @@ The following functions and structs are used to create
|
|||
:c:type:`PyAsyncMethods` with an added ``Py_`` prefix.
|
||||
For example, use:
|
||||
|
||||
* :c:data:`Py_tp_dealloc` to set :c:member:`PyTypeObject.tp_dealloc`
|
||||
* :c:data:`Py_nb_add` to set :c:member:`PyNumberMethods.nb_add`
|
||||
* :c:data:`Py_sq_length` to set :c:member:`PySequenceMethods.sq_length`
|
||||
* ``Py_tp_dealloc`` to set :c:member:`PyTypeObject.tp_dealloc`
|
||||
* ``Py_nb_add`` to set :c:member:`PyNumberMethods.nb_add`
|
||||
* ``Py_sq_length`` to set :c:member:`PySequenceMethods.sq_length`
|
||||
|
||||
An additional slot is supported that does not correspond to a
|
||||
:c:type:`!PyTypeObject` struct field:
|
||||
|
|
@ -628,7 +560,7 @@ The following functions and structs are used to create
|
|||
|
||||
If it is not possible to switch to a ``MANAGED`` flag (for example,
|
||||
for vectorcall or to support Python older than 3.12), specify the
|
||||
offset in :c:data:`Py_tp_members`.
|
||||
offset in :c:member:`Py_tp_members <PyTypeObject.tp_members>`.
|
||||
See :ref:`PyMemberDef documentation <pymemberdef-offsets>`
|
||||
for details.
|
||||
|
||||
|
|
@ -655,8 +587,8 @@ The following functions and structs are used to create
|
|||
under the :ref:`limited API <limited-c-api>`.
|
||||
|
||||
.. versionchanged:: 3.14
|
||||
The field :c:member:`~PyTypeObject.tp_vectorcall` can now be set
|
||||
using :c:data:`Py_tp_vectorcall`. See the field's documentation
|
||||
The field :c:member:`~PyTypeObject.tp_vectorcall` can now set
|
||||
using ``Py_tp_vectorcall``. See the field's documentation
|
||||
for details.
|
||||
|
||||
.. c:member:: void *pfunc
|
||||
|
|
@ -666,11 +598,10 @@ The following functions and structs are used to create
|
|||
|
||||
*pfunc* values may not be ``NULL``, except for the following slots:
|
||||
|
||||
* :c:data:`Py_tp_doc`
|
||||
* ``Py_tp_doc``
|
||||
* :c:data:`Py_tp_token` (for clarity, prefer :c:data:`Py_TP_USE_SPEC`
|
||||
rather than ``NULL``)
|
||||
|
||||
|
||||
.. c:macro:: Py_tp_token
|
||||
|
||||
A :c:member:`~PyType_Slot.slot` that records a static memory layout ID
|
||||
|
|
|
|||
|
|
@ -676,8 +676,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: destructor PyTypeObject.tp_dealloc
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_dealloc
|
||||
|
||||
A pointer to the instance destructor function. The function signature is::
|
||||
|
||||
void tp_dealloc(PyObject *self);
|
||||
|
|
@ -862,8 +860,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: getattrfunc PyTypeObject.tp_getattr
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_getattr
|
||||
|
||||
An optional pointer to the get-attribute-string function.
|
||||
|
||||
This field is deprecated. When it is defined, it should point to a function
|
||||
|
|
@ -881,8 +877,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: setattrfunc PyTypeObject.tp_setattr
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_setattr
|
||||
|
||||
An optional pointer to the function for setting and deleting attributes.
|
||||
|
||||
This field is deprecated. When it is defined, it should point to a function
|
||||
|
|
@ -915,8 +909,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: reprfunc PyTypeObject.tp_repr
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_repr
|
||||
|
||||
.. index:: pair: built-in function; repr
|
||||
|
||||
An optional pointer to a function that implements the built-in function
|
||||
|
|
@ -982,8 +974,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: hashfunc PyTypeObject.tp_hash
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_hash
|
||||
|
||||
.. index:: pair: built-in function; hash
|
||||
|
||||
An optional pointer to a function that implements the built-in function
|
||||
|
|
@ -1025,8 +1015,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: ternaryfunc PyTypeObject.tp_call
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_call
|
||||
|
||||
An optional pointer to a function that implements calling the object. This
|
||||
should be ``NULL`` if the object is not callable. The signature is the same as
|
||||
for :c:func:`PyObject_Call`::
|
||||
|
|
@ -1040,8 +1028,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: reprfunc PyTypeObject.tp_str
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_str
|
||||
|
||||
An optional pointer to a function that implements the built-in operation
|
||||
:func:`str`. (Note that :class:`str` is a type now, and :func:`str` calls the
|
||||
constructor for that type. This constructor calls :c:func:`PyObject_Str` to do
|
||||
|
|
@ -1067,8 +1053,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: getattrofunc PyTypeObject.tp_getattro
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_getattro
|
||||
|
||||
An optional pointer to the get-attribute function.
|
||||
|
||||
The signature is the same as for :c:func:`PyObject_GetAttr`::
|
||||
|
|
@ -1093,8 +1077,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: setattrofunc PyTypeObject.tp_setattro
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_setattro
|
||||
|
||||
An optional pointer to the function for setting and deleting attributes.
|
||||
|
||||
The signature is the same as for :c:func:`PyObject_SetAttr`::
|
||||
|
|
@ -1278,7 +1260,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
This bit indicates that instances of the class have a :attr:`~object.__dict__`
|
||||
attribute, and that the space for the dictionary is managed by the VM.
|
||||
|
||||
If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` must also be set.
|
||||
If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set.
|
||||
|
||||
The type traverse function must call :c:func:`PyObject_VisitManagedDict`
|
||||
and its clear function must call :c:func:`PyObject_ClearManagedDict`.
|
||||
|
|
@ -1296,8 +1278,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
This bit indicates that instances of the class should be weakly
|
||||
referenceable.
|
||||
|
||||
If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` must also be set.
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
**Inheritance:**
|
||||
|
|
@ -1351,8 +1331,8 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
.. c:macro:: Py_TPFLAGS_BASE_EXC_SUBCLASS
|
||||
.. c:macro:: Py_TPFLAGS_TYPE_SUBCLASS
|
||||
|
||||
Functions such as :c:func:`PyLong_Check` will call :c:func:`PyType_FastSubclass`
|
||||
with one of these flags to quickly determine if a type is a subclass
|
||||
These flags are used by functions such as
|
||||
:c:func:`PyLong_Check` to quickly determine if a type is a subclass
|
||||
of a built-in type; such specific checks are faster than a generic
|
||||
check, like :c:func:`PyObject_IsInstance`. Custom types that inherit
|
||||
from built-ins should have their :c:member:`~PyTypeObject.tp_flags`
|
||||
|
|
@ -1493,8 +1473,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: const char* PyTypeObject.tp_doc
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_doc
|
||||
|
||||
An optional pointer to a NUL-terminated C string giving the docstring for this
|
||||
type object. This is exposed as the :attr:`~type.__doc__` attribute on the
|
||||
type and instances of the type.
|
||||
|
|
@ -1506,8 +1484,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: traverseproc PyTypeObject.tp_traverse
|
||||
|
||||
.. 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::
|
||||
|
||||
|
|
@ -1569,11 +1545,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
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.
|
||||
|
|
@ -1609,8 +1580,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: inquiry PyTypeObject.tp_clear
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_clear
|
||||
|
||||
An optional pointer to a clear function. The signature is::
|
||||
|
||||
int tp_clear(PyObject *);
|
||||
|
|
@ -1759,8 +1728,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: richcmpfunc PyTypeObject.tp_richcompare
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_richcompare
|
||||
|
||||
An optional pointer to the rich comparison function, whose signature is::
|
||||
|
||||
PyObject *tp_richcompare(PyObject *self, PyObject *other, int op);
|
||||
|
|
@ -1863,8 +1830,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: getiterfunc PyTypeObject.tp_iter
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_iter
|
||||
|
||||
An optional pointer to a function that returns an :term:`iterator` for the
|
||||
object. Its presence normally signals that the instances of this type are
|
||||
:term:`iterable` (although sequences may be iterable without this function).
|
||||
|
|
@ -1880,8 +1845,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: iternextfunc PyTypeObject.tp_iternext
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_iternext
|
||||
|
||||
An optional pointer to a function that returns the next item in an
|
||||
:term:`iterator`. The signature is::
|
||||
|
||||
|
|
@ -1905,8 +1868,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: struct PyMethodDef* PyTypeObject.tp_methods
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_methods
|
||||
|
||||
An optional pointer to a static ``NULL``-terminated array of :c:type:`PyMethodDef`
|
||||
structures, declaring regular methods of this type.
|
||||
|
||||
|
|
@ -1921,8 +1882,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: struct PyMemberDef* PyTypeObject.tp_members
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_members
|
||||
|
||||
An optional pointer to a static ``NULL``-terminated array of :c:type:`PyMemberDef`
|
||||
structures, declaring regular data members (fields or slots) of instances of
|
||||
this type.
|
||||
|
|
@ -1938,8 +1897,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: struct PyGetSetDef* PyTypeObject.tp_getset
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_getset
|
||||
|
||||
An optional pointer to a static ``NULL``-terminated array of :c:type:`PyGetSetDef`
|
||||
structures, declaring computed attributes of instances of this type.
|
||||
|
||||
|
|
@ -1954,8 +1911,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: PyTypeObject* PyTypeObject.tp_base
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_base
|
||||
|
||||
An optional pointer to a base type from which type properties are inherited. At
|
||||
this level, only single inheritance is supported; multiple inheritance require
|
||||
dynamically creating a type object by calling the metatype.
|
||||
|
|
@ -2028,8 +1983,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: descrgetfunc PyTypeObject.tp_descr_get
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_descr_get
|
||||
|
||||
An optional pointer to a "descriptor get" function.
|
||||
|
||||
The function signature is::
|
||||
|
|
@ -2045,8 +1998,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: descrsetfunc PyTypeObject.tp_descr_set
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_descr_set
|
||||
|
||||
An optional pointer to a function for setting and deleting
|
||||
a descriptor's value.
|
||||
|
||||
|
|
@ -2107,8 +2058,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: initproc PyTypeObject.tp_init
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_init
|
||||
|
||||
An optional pointer to an instance initialization function.
|
||||
|
||||
This function corresponds to the :meth:`~object.__init__` method of classes. Like
|
||||
|
|
@ -2144,8 +2093,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: allocfunc PyTypeObject.tp_alloc
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_alloc
|
||||
|
||||
An optional pointer to an instance allocation function.
|
||||
|
||||
The function signature is::
|
||||
|
|
@ -2169,8 +2116,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: newfunc PyTypeObject.tp_new
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_new
|
||||
|
||||
An optional pointer to an instance creation function.
|
||||
|
||||
The function signature is::
|
||||
|
|
@ -2210,8 +2155,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: freefunc PyTypeObject.tp_free
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_free
|
||||
|
||||
An optional pointer to an instance deallocation function. Its signature is::
|
||||
|
||||
void tp_free(void *self);
|
||||
|
|
@ -2241,8 +2184,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: inquiry PyTypeObject.tp_is_gc
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_is_gc
|
||||
|
||||
An optional pointer to a function called by the garbage collector.
|
||||
|
||||
The garbage collector needs to know whether a particular object is collectible
|
||||
|
|
@ -2271,14 +2212,12 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: PyObject* PyTypeObject.tp_bases
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_bases
|
||||
|
||||
Tuple of base types.
|
||||
|
||||
This field should be set to ``NULL`` and treated as read-only.
|
||||
Python will fill it in when the type is :c:func:`initialized <PyType_Ready>`.
|
||||
|
||||
For dynamically created classes, the :c:data:`Py_tp_bases`
|
||||
For dynamically created classes, the ``Py_tp_bases``
|
||||
:c:type:`slot <PyType_Slot>` can be used instead of the *bases* argument
|
||||
of :c:func:`PyType_FromSpecWithBases`.
|
||||
The argument form is preferred.
|
||||
|
|
@ -2353,8 +2292,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: destructor PyTypeObject.tp_del
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_del
|
||||
|
||||
This field is deprecated. Use :c:member:`~PyTypeObject.tp_finalize` instead.
|
||||
|
||||
|
||||
|
|
@ -2369,8 +2306,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: destructor PyTypeObject.tp_finalize
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_finalize
|
||||
|
||||
An optional pointer to an instance finalization function. This is the C
|
||||
implementation of the :meth:`~object.__del__` special method. Its signature
|
||||
is::
|
||||
|
|
@ -2529,8 +2464,6 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. c:member:: vectorcallfunc PyTypeObject.tp_vectorcall
|
||||
|
||||
.. corresponding-type-slot:: Py_tp_vectorcall
|
||||
|
||||
A :ref:`vectorcall function <vectorcall>` to use for calls of this type
|
||||
object (rather than instances).
|
||||
In other words, ``tp_vectorcall`` can be used to optimize ``type.__call__``,
|
||||
|
|
@ -2696,148 +2629,42 @@ Number Object Structures
|
|||
Python 3.0.1.
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_add
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_add
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_subtract
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_subtract
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_multiply
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_multiply
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_remainder
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_remainder
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_divmod
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_divmod
|
||||
|
||||
.. c:member:: ternaryfunc PyNumberMethods.nb_power
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_power
|
||||
|
||||
.. c:member:: unaryfunc PyNumberMethods.nb_negative
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_negative
|
||||
|
||||
.. c:member:: unaryfunc PyNumberMethods.nb_positive
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_positive
|
||||
|
||||
.. c:member:: unaryfunc PyNumberMethods.nb_absolute
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_absolute
|
||||
|
||||
.. c:member:: inquiry PyNumberMethods.nb_bool
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_bool
|
||||
|
||||
.. c:member:: unaryfunc PyNumberMethods.nb_invert
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_invert
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_lshift
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_lshift
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_rshift
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_rshift
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_and
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_and
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_xor
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_xor
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_or
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_or
|
||||
|
||||
.. c:member:: unaryfunc PyNumberMethods.nb_int
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_int
|
||||
|
||||
.. c:member:: void *PyNumberMethods.nb_reserved
|
||||
|
||||
.. c:member:: unaryfunc PyNumberMethods.nb_float
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_float
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_inplace_add
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_inplace_add
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_inplace_subtract
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_inplace_subtract
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_inplace_multiply
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_inplace_multiply
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_inplace_remainder
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_inplace_remainder
|
||||
|
||||
.. c:member:: ternaryfunc PyNumberMethods.nb_inplace_power
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_inplace_power
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_inplace_lshift
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_inplace_lshift
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_inplace_rshift
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_inplace_rshift
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_inplace_and
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_inplace_and
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_inplace_xor
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_inplace_xor
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_inplace_or
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_inplace_or
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_floor_divide
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_floor_divide
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_true_divide
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_true_divide
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_inplace_floor_divide
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_inplace_floor_divide
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_inplace_true_divide
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_inplace_true_divide
|
||||
|
||||
.. c:member:: unaryfunc PyNumberMethods.nb_index
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_index
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_matrix_multiply
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_matrix_multiply
|
||||
|
||||
.. c:member:: binaryfunc PyNumberMethods.nb_inplace_matrix_multiply
|
||||
|
||||
.. corresponding-type-slot:: Py_nb_inplace_matrix_multiply
|
||||
|
||||
|
||||
|
||||
.. _mapping-structs:
|
||||
|
||||
|
|
@ -2854,16 +2681,12 @@ Mapping Object Structures
|
|||
|
||||
.. c:member:: lenfunc PyMappingMethods.mp_length
|
||||
|
||||
.. corresponding-type-slot:: Py_mp_length
|
||||
|
||||
This function is used by :c:func:`PyMapping_Size` and
|
||||
:c:func:`PyObject_Size`, and has the same signature. This slot may be set to
|
||||
``NULL`` if the object has no defined length.
|
||||
|
||||
.. c:member:: binaryfunc PyMappingMethods.mp_subscript
|
||||
|
||||
.. corresponding-type-slot:: Py_mp_subscript
|
||||
|
||||
This function is used by :c:func:`PyObject_GetItem` and
|
||||
:c:func:`PySequence_GetSlice`, and has the same signature as
|
||||
:c:func:`!PyObject_GetItem`. This slot must be filled for the
|
||||
|
|
@ -2872,8 +2695,6 @@ Mapping Object Structures
|
|||
|
||||
.. c:member:: objobjargproc PyMappingMethods.mp_ass_subscript
|
||||
|
||||
.. corresponding-type-slot:: Py_mp_ass_subscript
|
||||
|
||||
This function is used by :c:func:`PyObject_SetItem`,
|
||||
:c:func:`PyObject_DelItem`, :c:func:`PySequence_SetSlice` and
|
||||
:c:func:`PySequence_DelSlice`. It has the same signature as
|
||||
|
|
@ -2897,8 +2718,6 @@ Sequence Object Structures
|
|||
|
||||
.. c:member:: lenfunc PySequenceMethods.sq_length
|
||||
|
||||
.. corresponding-type-slot:: Py_sq_length
|
||||
|
||||
This function is used by :c:func:`PySequence_Size` and
|
||||
:c:func:`PyObject_Size`, and has the same signature. It is also used for
|
||||
handling negative indices via the :c:member:`~PySequenceMethods.sq_item`
|
||||
|
|
@ -2906,24 +2725,18 @@ Sequence Object Structures
|
|||
|
||||
.. c:member:: binaryfunc PySequenceMethods.sq_concat
|
||||
|
||||
.. corresponding-type-slot:: Py_sq_concat
|
||||
|
||||
This function is used by :c:func:`PySequence_Concat` and has the same
|
||||
signature. It is also used by the ``+`` operator, after trying the numeric
|
||||
addition via the :c:member:`~PyNumberMethods.nb_add` slot.
|
||||
|
||||
.. c:member:: ssizeargfunc PySequenceMethods.sq_repeat
|
||||
|
||||
.. corresponding-type-slot:: Py_sq_repeat
|
||||
|
||||
This function is used by :c:func:`PySequence_Repeat` and has the same
|
||||
signature. It is also used by the ``*`` operator, after trying numeric
|
||||
multiplication via the :c:member:`~PyNumberMethods.nb_multiply` slot.
|
||||
|
||||
.. c:member:: ssizeargfunc PySequenceMethods.sq_item
|
||||
|
||||
.. corresponding-type-slot:: Py_sq_item
|
||||
|
||||
This function is used by :c:func:`PySequence_GetItem` and has the same
|
||||
signature. It is also used by :c:func:`PyObject_GetItem`, after trying
|
||||
the subscription via the :c:member:`~PyMappingMethods.mp_subscript` slot.
|
||||
|
|
@ -2937,8 +2750,6 @@ Sequence Object Structures
|
|||
|
||||
.. c:member:: ssizeobjargproc PySequenceMethods.sq_ass_item
|
||||
|
||||
.. corresponding-type-slot:: Py_sq_ass_item
|
||||
|
||||
This function is used by :c:func:`PySequence_SetItem` and has the same
|
||||
signature. It is also used by :c:func:`PyObject_SetItem` and
|
||||
:c:func:`PyObject_DelItem`, after trying the item assignment and deletion
|
||||
|
|
@ -2948,8 +2759,6 @@ Sequence Object Structures
|
|||
|
||||
.. c:member:: objobjproc PySequenceMethods.sq_contains
|
||||
|
||||
.. corresponding-type-slot:: Py_sq_contains
|
||||
|
||||
This function may be used by :c:func:`PySequence_Contains` and has the same
|
||||
signature. This slot may be left to ``NULL``, in this case
|
||||
:c:func:`!PySequence_Contains` simply traverses the sequence until it
|
||||
|
|
@ -2957,8 +2766,6 @@ Sequence Object Structures
|
|||
|
||||
.. c:member:: binaryfunc PySequenceMethods.sq_inplace_concat
|
||||
|
||||
.. corresponding-type-slot:: Py_sq_inplace_concat
|
||||
|
||||
This function is used by :c:func:`PySequence_InPlaceConcat` and has the same
|
||||
signature. It should modify its first operand, and return it. This slot
|
||||
may be left to ``NULL``, in this case :c:func:`!PySequence_InPlaceConcat`
|
||||
|
|
@ -2968,8 +2775,6 @@ Sequence Object Structures
|
|||
|
||||
.. c:member:: ssizeargfunc PySequenceMethods.sq_inplace_repeat
|
||||
|
||||
.. corresponding-type-slot:: Py_sq_inplace_repeat
|
||||
|
||||
This function is used by :c:func:`PySequence_InPlaceRepeat` and has the same
|
||||
signature. It should modify its first operand, and return it. This slot
|
||||
may be left to ``NULL``, in this case :c:func:`!PySequence_InPlaceRepeat`
|
||||
|
|
@ -2995,8 +2800,6 @@ Buffer Object Structures
|
|||
|
||||
.. c:member:: getbufferproc PyBufferProcs.bf_getbuffer
|
||||
|
||||
.. corresponding-type-slot:: Py_bf_getbuffer
|
||||
|
||||
The signature of this function is::
|
||||
|
||||
int (PyObject *exporter, Py_buffer *view, int flags);
|
||||
|
|
@ -3046,8 +2849,6 @@ Buffer Object Structures
|
|||
|
||||
.. c:member:: releasebufferproc PyBufferProcs.bf_releasebuffer
|
||||
|
||||
.. corresponding-type-slot:: Py_bf_releasebuffer
|
||||
|
||||
The signature of this function is::
|
||||
|
||||
void (PyObject *exporter, Py_buffer *view);
|
||||
|
|
@ -3102,8 +2903,6 @@ Async Object Structures
|
|||
|
||||
.. c:member:: unaryfunc PyAsyncMethods.am_await
|
||||
|
||||
.. corresponding-type-slot:: Py_am_await
|
||||
|
||||
The signature of this function is::
|
||||
|
||||
PyObject *am_await(PyObject *self);
|
||||
|
|
@ -3115,8 +2914,6 @@ Async Object Structures
|
|||
|
||||
.. c:member:: unaryfunc PyAsyncMethods.am_aiter
|
||||
|
||||
.. corresponding-type-slot:: Py_am_aiter
|
||||
|
||||
The signature of this function is::
|
||||
|
||||
PyObject *am_aiter(PyObject *self);
|
||||
|
|
@ -3129,8 +2926,6 @@ Async Object Structures
|
|||
|
||||
.. c:member:: unaryfunc PyAsyncMethods.am_anext
|
||||
|
||||
.. corresponding-type-slot:: Py_am_anext
|
||||
|
||||
The signature of this function is::
|
||||
|
||||
PyObject *am_anext(PyObject *self);
|
||||
|
|
@ -3141,8 +2936,6 @@ Async Object Structures
|
|||
|
||||
.. c:member:: sendfunc PyAsyncMethods.am_send
|
||||
|
||||
.. corresponding-type-slot:: Py_am_send
|
||||
|
||||
The signature of this function is::
|
||||
|
||||
PySendResult am_send(PyObject *self, PyObject *arg, PyObject **result);
|
||||
|
|
|
|||
|
|
@ -321,22 +321,12 @@ These APIs can be used to work with surrogates:
|
|||
|
||||
Check if *ch* is a low surrogate (``0xDC00 <= ch <= 0xDFFF``).
|
||||
|
||||
.. c:function:: Py_UCS4 Py_UNICODE_HIGH_SURROGATE(Py_UCS4 ch)
|
||||
|
||||
Return the high UTF-16 surrogate (``0xD800`` to ``0xDBFF``) for a Unicode
|
||||
code point in the range ``[0x10000; 0x10FFFF]``.
|
||||
|
||||
.. c:function:: Py_UCS4 Py_UNICODE_LOW_SURROGATE(Py_UCS4 ch)
|
||||
|
||||
Return the low UTF-16 surrogate (``0xDC00`` to ``0xDFFF``) for a Unicode
|
||||
code point in the range ``[0x10000; 0x10FFFF]``.
|
||||
|
||||
.. c:function:: Py_UCS4 Py_UNICODE_JOIN_SURROGATES(Py_UCS4 high, Py_UCS4 low)
|
||||
|
||||
Join two surrogate code points and return a single :c:type:`Py_UCS4` value.
|
||||
*high* and *low* are respectively the leading and trailing surrogates in a
|
||||
surrogate pair. *high* must be in the range ``[0xD800; 0xDBFF]`` and *low* must
|
||||
be in the range ``[0xDC00; 0xDFFF]``.
|
||||
surrogate pair. *high* must be in the range [0xD800; 0xDBFF] and *low* must
|
||||
be in the range [0xDC00; 0xDFFF].
|
||||
|
||||
|
||||
Creating and accessing Unicode strings
|
||||
|
|
|
|||
|
|
@ -13,9 +13,8 @@ the interpreter.
|
|||
|
||||
Several of these functions accept a start symbol from the grammar as a
|
||||
parameter. The available start symbols are :c:data:`Py_eval_input`,
|
||||
:c:data:`Py_file_input`, :c:data:`Py_single_input`, and
|
||||
:c:data:`Py_func_type_input`. These are described following the functions
|
||||
which accept them as parameters.
|
||||
:c:data:`Py_file_input`, and :c:data:`Py_single_input`. These are described
|
||||
following the functions which accept them as parameters.
|
||||
|
||||
Note also that several of these functions take :c:expr:`FILE*` parameters. One
|
||||
particular issue which needs to be handled carefully is that the :c:type:`FILE`
|
||||
|
|
@ -100,20 +99,6 @@ the same library that the Python runtime is using.
|
|||
Otherwise, Python may not handle script file with LF line ending correctly.
|
||||
|
||||
|
||||
.. c:function:: int PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags)
|
||||
|
||||
Read and execute a single statement from a file associated with an
|
||||
interactive device according to the *flags* argument. The user will be
|
||||
prompted using ``sys.ps1`` and ``sys.ps2``. *filename* must be a Python
|
||||
:class:`str` object.
|
||||
|
||||
Returns ``0`` when the input was
|
||||
executed successfully, ``-1`` if there was an exception, or an error code
|
||||
from the :file:`errcode.h` include file distributed as part of Python if
|
||||
there was a parse error. (Note that :file:`errcode.h` is not included by
|
||||
:file:`Python.h`, so must be included specifically if needed.)
|
||||
|
||||
|
||||
.. c:function:: int PyRun_InteractiveOne(FILE *fp, const char *filename)
|
||||
|
||||
This is a simplified interface to :c:func:`PyRun_InteractiveOneFlags` below,
|
||||
|
|
@ -122,10 +107,17 @@ the same library that the Python runtime is using.
|
|||
|
||||
.. c:function:: int PyRun_InteractiveOneFlags(FILE *fp, const char *filename, PyCompilerFlags *flags)
|
||||
|
||||
Similar to :c:func:`PyRun_InteractiveOneObject`, but *filename* is a
|
||||
:c:expr:`const char*`, which is decoded from the
|
||||
Read and execute a single statement from a file associated with an
|
||||
interactive device according to the *flags* argument. The user will be
|
||||
prompted using ``sys.ps1`` and ``sys.ps2``. *filename* is decoded from the
|
||||
:term:`filesystem encoding and error handler`.
|
||||
|
||||
Returns ``0`` when the input was
|
||||
executed successfully, ``-1`` if there was an exception, or an error code
|
||||
from the :file:`errcode.h` include file distributed as part of Python if
|
||||
there was a parse error. (Note that :file:`errcode.h` is not included by
|
||||
:file:`Python.h`, so must be included specifically if needed.)
|
||||
|
||||
|
||||
.. c:function:: int PyRun_InteractiveLoop(FILE *fp, const char *filename)
|
||||
|
||||
|
|
@ -148,7 +140,7 @@ the same library that the Python runtime is using.
|
|||
interpreter prompt is about to become idle and wait for user input
|
||||
from the terminal. The return value is ignored. Overriding this
|
||||
hook can be used to integrate the interpreter's prompt with other
|
||||
event loops, as done in :file:`Modules/_tkinter.c` in the
|
||||
event loops, as done in the :file:`Modules/_tkinter.c` in the
|
||||
Python source code.
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
|
|
@ -191,7 +183,8 @@ 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 one of the following:
|
||||
:c:data:`Py_eval_input`, :c:data:`Py_file_input`, or :c:data:`Py_single_input`.
|
||||
|
||||
Returns the result of executing the code as a Python object, or ``NULL`` if an
|
||||
exception was raised.
|
||||
|
|
@ -240,8 +233,8 @@ the same library that the Python runtime is using.
|
|||
|
||||
Parse and compile the Python source code in *str*, returning the resulting code
|
||||
object. The start symbol is given by *start*; this can be used to constrain the
|
||||
code which can be compiled and should be :ref:`available start symbols
|
||||
<start-symbols>`. The filename specified by
|
||||
code which can be compiled and should be :c:data:`Py_eval_input`,
|
||||
:c:data:`Py_file_input`, or :c:data:`Py_single_input`. The filename specified by
|
||||
*filename* is used to construct the code object and may appear in tracebacks or
|
||||
:exc:`SyntaxError` exception messages. This returns ``NULL`` if the code
|
||||
cannot be parsed or compiled.
|
||||
|
|
@ -304,6 +297,32 @@ the same library that the Python runtime is using.
|
|||
true on success, false on failure.
|
||||
|
||||
|
||||
.. c:var:: int Py_eval_input
|
||||
|
||||
.. index:: single: Py_CompileString (C function)
|
||||
|
||||
The start symbol from the Python grammar for isolated expressions; for use with
|
||||
:c:func:`Py_CompileString`.
|
||||
|
||||
|
||||
.. c:var:: int Py_file_input
|
||||
|
||||
.. index:: single: Py_CompileString (C function)
|
||||
|
||||
The start symbol from the Python grammar for sequences of statements as read
|
||||
from a file or other source; for use with :c:func:`Py_CompileString`. This is
|
||||
the symbol to use when compiling arbitrarily long Python source code.
|
||||
|
||||
|
||||
.. c:var:: int Py_single_input
|
||||
|
||||
.. index:: single: Py_CompileString (C function)
|
||||
|
||||
The start symbol from the Python grammar for a single statement; for use with
|
||||
:c:func:`Py_CompileString`. This is the symbol used for the interactive
|
||||
interpreter loop.
|
||||
|
||||
|
||||
.. c:struct:: PyCompilerFlags
|
||||
|
||||
This is the structure used to hold compiler flags. In cases where code is only
|
||||
|
|
@ -347,92 +366,3 @@ the same library that the Python runtime is using.
|
|||
as :c:macro:`CO_FUTURE_ANNOTATIONS` to enable features normally
|
||||
selectable using :ref:`future statements <future>`.
|
||||
See :ref:`c_codeobject_flags` for a complete list.
|
||||
|
||||
|
||||
.. _start-symbols:
|
||||
|
||||
Available start symbols
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
.. c:var:: int Py_eval_input
|
||||
|
||||
.. index:: single: Py_CompileString (C function)
|
||||
|
||||
The start symbol from the Python grammar for isolated expressions; for use with
|
||||
:c:func:`Py_CompileString`.
|
||||
|
||||
|
||||
.. c:var:: int Py_file_input
|
||||
|
||||
.. index:: single: Py_CompileString (C function)
|
||||
|
||||
The start symbol from the Python grammar for sequences of statements as read
|
||||
from a file or other source; for use with :c:func:`Py_CompileString`. This is
|
||||
the symbol to use when compiling arbitrarily long Python source code.
|
||||
|
||||
|
||||
.. c:var:: int Py_single_input
|
||||
|
||||
.. index:: single: Py_CompileString (C function)
|
||||
|
||||
The start symbol from the Python grammar for a single statement; for use with
|
||||
:c:func:`Py_CompileString`. This is the symbol used for the interactive
|
||||
interpreter loop.
|
||||
|
||||
|
||||
.. c:var:: int Py_func_type_input
|
||||
|
||||
.. index:: single: Py_CompileString (C function)
|
||||
|
||||
The start symbol from the Python grammar for a function type; for use with
|
||||
:c:func:`Py_CompileString`. This is used to parse "signature type comments"
|
||||
from :pep:`484`.
|
||||
|
||||
This requires the :c:macro:`PyCF_ONLY_AST` flag to be set.
|
||||
|
||||
.. seealso::
|
||||
* :py:class:`ast.FunctionType`
|
||||
* :pep:`484`
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
Stack Effects
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
.. seealso::
|
||||
:py:func:`dis.stack_effect`
|
||||
|
||||
|
||||
.. c:macro:: PY_INVALID_STACK_EFFECT
|
||||
|
||||
Sentinel value representing an invalid stack effect.
|
||||
|
||||
This is currently equivalent to ``INT_MAX``.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
.. c:function:: int PyCompile_OpcodeStackEffect(int opcode, int oparg)
|
||||
|
||||
Compute the stack effect of *opcode* with argument *oparg*.
|
||||
|
||||
On success, this function returns the stack effect; on failure, this
|
||||
returns :c:macro:`PY_INVALID_STACK_EFFECT`.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
|
||||
.. c:function:: int PyCompile_OpcodeStackEffectWithJump(int opcode, int oparg, int jump)
|
||||
|
||||
Similar to :c:func:`PyCompile_OpcodeStackEffect`, but don't include the
|
||||
stack effect of jumping if *jump* is zero.
|
||||
|
||||
If *jump* is ``0``, this will not include the stack effect of jumping, but
|
||||
if *jump* is ``1`` or ``-1``, this will include it.
|
||||
|
||||
On success, this function returns the stack effect; on failure, this
|
||||
returns :c:macro:`PY_INVALID_STACK_EFFECT`.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
|
|
|||
|
|
@ -19,14 +19,7 @@ as much as it can.
|
|||
|
||||
.. c:function:: int PyWeakref_CheckRef(PyObject *ob)
|
||||
|
||||
Return non-zero if *ob* is a reference object or a subclass of the reference
|
||||
type. This function always succeeds.
|
||||
|
||||
|
||||
.. c:function:: int PyWeakref_CheckRefExact(PyObject *ob)
|
||||
|
||||
Return non-zero if *ob* is a reference object, but not a subclass of the
|
||||
reference type. This function always succeeds.
|
||||
Return non-zero if *ob* is a reference object. This function always succeeds.
|
||||
|
||||
|
||||
.. c:function:: int PyWeakref_CheckProxy(PyObject *ob)
|
||||
|
|
@ -45,10 +38,6 @@ as much as it can.
|
|||
weakly referenceable object, or if *callback* is not callable, ``None``, or
|
||||
``NULL``, this will return ``NULL`` and raise :exc:`TypeError`.
|
||||
|
||||
.. seealso::
|
||||
:c:func:`PyType_SUPPORTS_WEAKREFS` for checking if *ob* is weakly
|
||||
referenceable.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
|
||||
|
||||
|
|
@ -61,10 +50,6 @@ as much as it can.
|
|||
is not a weakly referenceable object, or if *callback* is not callable,
|
||||
``None``, or ``NULL``, this will return ``NULL`` and raise :exc:`TypeError`.
|
||||
|
||||
.. seealso::
|
||||
:c:func:`PyType_SUPPORTS_WEAKREFS` for checking if *ob* is weakly
|
||||
referenceable.
|
||||
|
||||
|
||||
.. c:function:: int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
|
||||
|
||||
|
|
|
|||
32
Doc/conf.py
32
Doc/conf.py
|
|
@ -226,6 +226,9 @@ nitpick_ignore = [
|
|||
# Temporary undocumented names.
|
||||
# In future this list must be empty.
|
||||
nitpick_ignore += [
|
||||
# Undocumented public C macros
|
||||
('c:macro', 'Py_BUILD_ASSERT'),
|
||||
('c:macro', 'Py_BUILD_ASSERT_EXPR'),
|
||||
# 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.
|
||||
|
|
@ -356,12 +359,11 @@ latex_elements = {
|
|||
'papersize': 'a4paper',
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
'pointsize': '10pt',
|
||||
'maxlistdepth': '8', # See https://github.com/python/cpython/issues/139588
|
||||
}
|
||||
|
||||
# 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'
|
||||
_stdauthor = 'Guido van Rossum and the Python development team'
|
||||
latex_documents = [
|
||||
('c-api/index', 'c-api.tex', 'The Python/C API', _stdauthor, 'manual'),
|
||||
(
|
||||
|
|
@ -436,36 +438,12 @@ latex_appendices = ['glossary', 'about', 'license', 'copyright']
|
|||
|
||||
epub_author = 'Python Documentation Authors'
|
||||
epub_publisher = 'Python Software Foundation'
|
||||
epub_exclude_files = (
|
||||
'index.xhtml',
|
||||
'download.xhtml',
|
||||
'_static/tachyon-example-flamegraph.html',
|
||||
'_static/tachyon-example-heatmap.html',
|
||||
)
|
||||
epub_exclude_files = ('index.xhtml', 'download.xhtml')
|
||||
|
||||
# index pages are not valid xhtml
|
||||
# https://github.com/sphinx-doc/sphinx/issues/12359
|
||||
epub_use_index = False
|
||||
|
||||
# translation tag
|
||||
# ---------------
|
||||
|
||||
language_code = None
|
||||
for arg in sys.argv:
|
||||
if arg.startswith('language='):
|
||||
language_code = arg.split('=', 1)[1]
|
||||
|
||||
if language_code:
|
||||
tags.add('translation') # noqa: F821
|
||||
|
||||
rst_epilog += f"""\
|
||||
.. _TRANSLATION_REPO: https://github.com/python/python-docs-{language_code.replace("_", "-").lower()}
|
||||
""" # noqa: F821
|
||||
else:
|
||||
rst_epilog += """\
|
||||
.. _TRANSLATION_REPO: https://github.com/python
|
||||
"""
|
||||
|
||||
# Options for the coverage checker
|
||||
# --------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1472,9 +1472,6 @@ PyModule_Create2:PyObject*::+1:
|
|||
PyModule_Create2:PyModuleDef*:def::
|
||||
PyModule_Create2:int:module_api_version::
|
||||
|
||||
PyModule_Exec:int:::
|
||||
PyModule_ExecDef:PyObject*:module:0:
|
||||
|
||||
PyModule_ExecDef:int:::
|
||||
PyModule_ExecDef:PyObject*:module:0:
|
||||
PyModule_ExecDef:PyModuleDef*:def::
|
||||
|
|
@ -1488,10 +1485,6 @@ PyModule_FromDefAndSpec2:PyModuleDef*:def::
|
|||
PyModule_FromDefAndSpec2:PyObject*:spec:0:
|
||||
PyModule_FromDefAndSpec2:int:module_api_version::
|
||||
|
||||
PyModule_FromSlotsAndSpec:PyObject*::+1:
|
||||
PyModule_FromSlotsAndSpec:const PyModuleDef_Slot *:slots::
|
||||
PyModule_FromSlotsAndSpec:PyObject*:spec:0:
|
||||
|
||||
PyModule_GetDef:PyModuleDef*::0:
|
||||
PyModule_GetDef:PyObject*:module:0:
|
||||
|
||||
|
|
@ -1513,14 +1506,6 @@ PyModule_GetNameObject:PyObject*:module:0:
|
|||
PyModule_GetState:void*:::
|
||||
PyModule_GetState:PyObject*:module:0:
|
||||
|
||||
PyModule_GetStateSize:int:::
|
||||
PyModule_GetStateSize:PyObject*:module:0:
|
||||
PyModule_GetToken:Py_ssize_t**:result::
|
||||
|
||||
PyModule_GetToken:int:::
|
||||
PyModule_GetToken:PyObject*:module:0:
|
||||
PyModule_GetToken:void**:result::
|
||||
|
||||
PyModule_New:PyObject*::+1:
|
||||
PyModule_New:char*:name::
|
||||
|
||||
|
|
@ -2427,10 +2412,6 @@ PyType_GetFlags:PyTypeObject*:type:0:
|
|||
PyType_GetName:PyObject*::+1:
|
||||
PyType_GetName:PyTypeObject*:type:0:
|
||||
|
||||
PyType_GetModuleByToken:PyObject*::+1:
|
||||
PyType_GetModuleByToken:PyTypeObject*:type:0:
|
||||
PyType_GetModuleByToken:PyModuleDef*:def::
|
||||
|
||||
PyType_GetModuleByDef:PyObject*::0:
|
||||
PyType_GetModuleByDef:PyTypeObject*:type:0:
|
||||
PyType_GetModuleByDef:PyModuleDef*:def::
|
||||
|
|
|
|||
176
Doc/data/stable_abi.dat
generated
176
Doc/data/stable_abi.dat
generated
|
|
@ -1,21 +1,7 @@
|
|||
role,name,added,ifdef_note,struct_abi_kind
|
||||
macro,METH_CLASS,3.2,,
|
||||
macro,METH_COEXIST,3.2,,
|
||||
macro,METH_FASTCALL,3.7,,
|
||||
macro,METH_METHOD,3.7,,
|
||||
macro,METH_NOARGS,3.2,,
|
||||
macro,METH_O,3.2,,
|
||||
macro,METH_STATIC,3.2,,
|
||||
macro,METH_VARARGS,3.2,,
|
||||
macro,PY_VECTORCALL_ARGUMENTS_OFFSET,3.12,,
|
||||
type,PyABIInfo,3.15,,full-abi
|
||||
func,PyABIInfo_Check,3.15,,
|
||||
macro,PyABIInfo_DEFAULT_ABI_VERSION,3.15,,
|
||||
macro,PyABIInfo_DEFAULT_FLAGS,3.15,,
|
||||
macro,PyABIInfo_FREETHREADED,3.15,,
|
||||
macro,PyABIInfo_FREETHREADING_AGNOSTIC,3.15,,
|
||||
macro,PyABIInfo_GIL,3.15,,
|
||||
macro,PyABIInfo_STABLE,3.15,,
|
||||
macro,PyABIInfo_VAR,3.15,,
|
||||
func,PyAIter_Check,3.10,,
|
||||
func,PyArg_Parse,3.2,,
|
||||
|
|
@ -25,26 +11,6 @@ func,PyArg_UnpackTuple,3.2,,
|
|||
func,PyArg_VaParse,3.2,,
|
||||
func,PyArg_VaParseTupleAndKeywords,3.2,,
|
||||
func,PyArg_ValidateKeywordArguments,3.2,,
|
||||
macro,PyBUF_ANY_CONTIGUOUS,3.11,,
|
||||
macro,PyBUF_CONTIG,3.11,,
|
||||
macro,PyBUF_CONTIG_RO,3.11,,
|
||||
macro,PyBUF_C_CONTIGUOUS,3.11,,
|
||||
macro,PyBUF_FORMAT,3.11,,
|
||||
macro,PyBUF_FULL,3.11,,
|
||||
macro,PyBUF_FULL_RO,3.11,,
|
||||
macro,PyBUF_F_CONTIGUOUS,3.11,,
|
||||
macro,PyBUF_INDIRECT,3.11,,
|
||||
macro,PyBUF_MAX_NDIM,3.11,,
|
||||
macro,PyBUF_ND,3.11,,
|
||||
macro,PyBUF_READ,3.11,,
|
||||
macro,PyBUF_RECORDS,3.11,,
|
||||
macro,PyBUF_RECORDS_RO,3.11,,
|
||||
macro,PyBUF_SIMPLE,3.11,,
|
||||
macro,PyBUF_STRIDED,3.11,,
|
||||
macro,PyBUF_STRIDED_RO,3.11,,
|
||||
macro,PyBUF_STRIDES,3.11,,
|
||||
macro,PyBUF_WRITABLE,3.11,,
|
||||
macro,PyBUF_WRITE,3.11,,
|
||||
data,PyBaseObject_Type,3.2,,
|
||||
func,PyBool_FromLong,3.2,,
|
||||
data,PyBool_Type,3.2,,
|
||||
|
|
@ -160,7 +126,6 @@ func,PyDict_Merge,3.2,,
|
|||
func,PyDict_MergeFromSeq2,3.2,,
|
||||
func,PyDict_New,3.2,,
|
||||
func,PyDict_Next,3.2,,
|
||||
func,PyDict_SetDefaultRef,3.15,,
|
||||
func,PyDict_SetItem,3.2,,
|
||||
func,PyDict_SetItemString,3.2,,
|
||||
func,PyDict_Size,3.2,,
|
||||
|
|
@ -426,7 +391,6 @@ func,PyLong_FromUnsignedNativeBytes,3.14,,
|
|||
func,PyLong_FromVoidPtr,3.2,,
|
||||
func,PyLong_GetInfo,3.2,,
|
||||
data,PyLong_Type,3.2,,
|
||||
macro,PyMODEXPORT_FUNC,3.15,,
|
||||
data,PyMap_Type,3.2,,
|
||||
func,PyMapping_Check,3.2,,
|
||||
func,PyMapping_GetItemString,3.2,,
|
||||
|
|
@ -464,7 +428,6 @@ data,PyMethodDescr_Type,3.2,,
|
|||
type,PyModuleDef,3.2,,full-abi
|
||||
type,PyModuleDef_Base,3.2,,full-abi
|
||||
func,PyModuleDef_Init,3.5,,
|
||||
type,PyModuleDef_Slot,3.5,,full-abi
|
||||
data,PyModuleDef_Type,3.5,,
|
||||
func,PyModule_Add,3.13,,
|
||||
func,PyModule_AddFunctions,3.7,,
|
||||
|
|
@ -474,10 +437,8 @@ func,PyModule_AddObjectRef,3.10,,
|
|||
func,PyModule_AddStringConstant,3.2,,
|
||||
func,PyModule_AddType,3.10,,
|
||||
func,PyModule_Create2,3.2,,
|
||||
func,PyModule_Exec,3.15,,
|
||||
func,PyModule_ExecDef,3.7,,
|
||||
func,PyModule_FromDefAndSpec2,3.7,,
|
||||
func,PyModule_FromSlotsAndSpec,3.15,,
|
||||
func,PyModule_GetDef,3.2,,
|
||||
func,PyModule_GetDict,3.2,,
|
||||
func,PyModule_GetFilename,3.2,,
|
||||
|
|
@ -485,8 +446,6 @@ func,PyModule_GetFilenameObject,3.2,,
|
|||
func,PyModule_GetName,3.2,,
|
||||
func,PyModule_GetNameObject,3.7,,
|
||||
func,PyModule_GetState,3.2,,
|
||||
func,PyModule_GetStateSize,3.15,,
|
||||
func,PyModule_GetToken,3.15,,
|
||||
func,PyModule_New,3.2,,
|
||||
func,PyModule_NewObject,3.7,,
|
||||
func,PyModule_SetDocString,3.7,,
|
||||
|
|
@ -745,7 +704,6 @@ 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_GetModuleName,3.13,,
|
||||
func,PyType_GetModuleState,3.10,,
|
||||
func,PyType_GetName,3.11,,
|
||||
|
|
@ -878,14 +836,6 @@ func,PyWeakref_NewRef,3.2,,
|
|||
data,PyWrapperDescr_Type,3.2,,
|
||||
func,PyWrapper_New,3.2,,
|
||||
data,PyZip_Type,3.2,,
|
||||
macro,Py_ASNATIVEBYTES_ALLOW_INDEX,3.14,,
|
||||
macro,Py_ASNATIVEBYTES_BIG_ENDIAN,3.14,,
|
||||
macro,Py_ASNATIVEBYTES_DEFAULTS,3.14,,
|
||||
macro,Py_ASNATIVEBYTES_LITTLE_ENDIAN,3.14,,
|
||||
macro,Py_ASNATIVEBYTES_NATIVE_ENDIAN,3.14,,
|
||||
macro,Py_ASNATIVEBYTES_REJECT_NEGATIVE,3.14,,
|
||||
macro,Py_ASNATIVEBYTES_UNSIGNED_BUFFER,3.14,,
|
||||
macro,Py_AUDIT_READ,3.12,,
|
||||
func,Py_AddPendingCall,3.2,,
|
||||
func,Py_AtExit,3.2,,
|
||||
macro,Py_BEGIN_ALLOW_THREADS,3.2,,
|
||||
|
|
@ -916,7 +866,6 @@ func,Py_GetPlatform,3.2,,
|
|||
func,Py_GetRecursionLimit,3.2,,
|
||||
func,Py_GetVersion,3.2,,
|
||||
data,Py_HasFileSystemDefaultEncoding,3.2,,
|
||||
func,Py_IS_TYPE,3.15,,
|
||||
func,Py_IncRef,3.2,,
|
||||
func,Py_Initialize,3.2,,
|
||||
func,Py_InitializeEx,3.2,,
|
||||
|
|
@ -933,147 +882,22 @@ func,Py_NewInterpreter,3.2,,
|
|||
func,Py_NewRef,3.10,,
|
||||
func,Py_PACK_FULL_VERSION,3.14,,
|
||||
func,Py_PACK_VERSION,3.14,,
|
||||
macro,Py_READONLY,3.12,,
|
||||
func,Py_REFCNT,3.14,,
|
||||
macro,Py_RELATIVE_OFFSET,3.12,,
|
||||
func,Py_ReprEnter,3.2,,
|
||||
func,Py_ReprLeave,3.2,,
|
||||
func,Py_SET_SIZE,3.15,,
|
||||
func,Py_SIZE,3.15,,
|
||||
func,Py_SetProgramName,3.2,,
|
||||
func,Py_SetPythonHome,3.2,,
|
||||
func,Py_SetRecursionLimit,3.2,,
|
||||
macro,Py_TPFLAGS_BASETYPE,3.2,,
|
||||
macro,Py_TPFLAGS_DEFAULT,3.2,,
|
||||
macro,Py_TPFLAGS_HAVE_GC,3.2,,
|
||||
macro,Py_TPFLAGS_HAVE_VECTORCALL,3.12,,
|
||||
macro,Py_TPFLAGS_ITEMS_AT_END,3.12,,
|
||||
macro,Py_TPFLAGS_METHOD_DESCRIPTOR,3.8,,
|
||||
macro,Py_TP_USE_SPEC,3.14,,
|
||||
func,Py_TYPE,3.14,,
|
||||
macro,Py_T_BOOL,3.12,,
|
||||
macro,Py_T_BYTE,3.12,,
|
||||
macro,Py_T_CHAR,3.12,,
|
||||
macro,Py_T_DOUBLE,3.12,,
|
||||
macro,Py_T_FLOAT,3.12,,
|
||||
macro,Py_T_INT,3.12,,
|
||||
macro,Py_T_LONG,3.12,,
|
||||
macro,Py_T_LONGLONG,3.12,,
|
||||
macro,Py_T_OBJECT_EX,3.12,,
|
||||
macro,Py_T_PYSSIZET,3.12,,
|
||||
macro,Py_T_SHORT,3.12,,
|
||||
macro,Py_T_STRING,3.12,,
|
||||
macro,Py_T_STRING_INPLACE,3.12,,
|
||||
macro,Py_T_UBYTE,3.12,,
|
||||
macro,Py_T_UINT,3.12,,
|
||||
macro,Py_T_ULONG,3.12,,
|
||||
macro,Py_T_ULONGLONG,3.12,,
|
||||
macro,Py_T_USHORT,3.12,,
|
||||
type,Py_UCS4,3.2,,
|
||||
macro,Py_UNBLOCK_THREADS,3.2,,
|
||||
data,Py_UTF8Mode,3.8,,
|
||||
func,Py_VaBuildValue,3.2,,
|
||||
data,Py_Version,3.11,,
|
||||
func,Py_XNewRef,3.10,,
|
||||
macro,Py_am_aiter,3.5,,
|
||||
macro,Py_am_anext,3.5,,
|
||||
macro,Py_am_await,3.5,,
|
||||
macro,Py_am_send,3.10,,
|
||||
macro,Py_bf_getbuffer,3.11,,
|
||||
macro,Py_bf_releasebuffer,3.11,,
|
||||
type,Py_buffer,3.11,,full-abi
|
||||
type,Py_intptr_t,3.2,,
|
||||
macro,Py_mod_abi,3.15,,
|
||||
macro,Py_mod_create,3.5,,
|
||||
macro,Py_mod_doc,3.15,,
|
||||
macro,Py_mod_exec,3.5,,
|
||||
macro,Py_mod_gil,3.13,,
|
||||
macro,Py_mod_methods,3.15,,
|
||||
macro,Py_mod_multiple_interpreters,3.12,,
|
||||
macro,Py_mod_name,3.15,,
|
||||
macro,Py_mod_state_clear,3.15,,
|
||||
macro,Py_mod_state_free,3.15,,
|
||||
macro,Py_mod_state_size,3.15,,
|
||||
macro,Py_mod_state_traverse,3.15,,
|
||||
macro,Py_mod_token,3.15,,
|
||||
macro,Py_mp_ass_subscript,3.2,,
|
||||
macro,Py_mp_length,3.2,,
|
||||
macro,Py_mp_subscript,3.2,,
|
||||
macro,Py_nb_absolute,3.2,,
|
||||
macro,Py_nb_add,3.2,,
|
||||
macro,Py_nb_and,3.2,,
|
||||
macro,Py_nb_bool,3.2,,
|
||||
macro,Py_nb_divmod,3.2,,
|
||||
macro,Py_nb_float,3.2,,
|
||||
macro,Py_nb_floor_divide,3.2,,
|
||||
macro,Py_nb_index,3.2,,
|
||||
macro,Py_nb_inplace_add,3.2,,
|
||||
macro,Py_nb_inplace_and,3.2,,
|
||||
macro,Py_nb_inplace_floor_divide,3.2,,
|
||||
macro,Py_nb_inplace_lshift,3.2,,
|
||||
macro,Py_nb_inplace_matrix_multiply,3.5,,
|
||||
macro,Py_nb_inplace_multiply,3.2,,
|
||||
macro,Py_nb_inplace_or,3.2,,
|
||||
macro,Py_nb_inplace_power,3.2,,
|
||||
macro,Py_nb_inplace_remainder,3.2,,
|
||||
macro,Py_nb_inplace_rshift,3.2,,
|
||||
macro,Py_nb_inplace_subtract,3.2,,
|
||||
macro,Py_nb_inplace_true_divide,3.2,,
|
||||
macro,Py_nb_inplace_xor,3.2,,
|
||||
macro,Py_nb_int,3.2,,
|
||||
macro,Py_nb_invert,3.2,,
|
||||
macro,Py_nb_lshift,3.2,,
|
||||
macro,Py_nb_matrix_multiply,3.5,,
|
||||
macro,Py_nb_multiply,3.2,,
|
||||
macro,Py_nb_negative,3.2,,
|
||||
macro,Py_nb_or,3.2,,
|
||||
macro,Py_nb_positive,3.2,,
|
||||
macro,Py_nb_power,3.2,,
|
||||
macro,Py_nb_remainder,3.2,,
|
||||
macro,Py_nb_rshift,3.2,,
|
||||
macro,Py_nb_subtract,3.2,,
|
||||
macro,Py_nb_true_divide,3.2,,
|
||||
macro,Py_nb_xor,3.2,,
|
||||
macro,Py_sq_ass_item,3.2,,
|
||||
macro,Py_sq_concat,3.2,,
|
||||
macro,Py_sq_contains,3.2,,
|
||||
macro,Py_sq_inplace_concat,3.2,,
|
||||
macro,Py_sq_inplace_repeat,3.2,,
|
||||
macro,Py_sq_item,3.2,,
|
||||
macro,Py_sq_length,3.2,,
|
||||
macro,Py_sq_repeat,3.2,,
|
||||
type,Py_ssize_t,3.2,,
|
||||
macro,Py_tp_alloc,3.2,,
|
||||
macro,Py_tp_base,3.2,,
|
||||
macro,Py_tp_bases,3.2,,
|
||||
macro,Py_tp_call,3.2,,
|
||||
macro,Py_tp_clear,3.2,,
|
||||
macro,Py_tp_dealloc,3.2,,
|
||||
macro,Py_tp_del,3.2,,
|
||||
macro,Py_tp_descr_get,3.2,,
|
||||
macro,Py_tp_descr_set,3.2,,
|
||||
macro,Py_tp_doc,3.2,,
|
||||
macro,Py_tp_finalize,3.5,,
|
||||
macro,Py_tp_free,3.2,,
|
||||
macro,Py_tp_getattr,3.2,,
|
||||
macro,Py_tp_getattro,3.2,,
|
||||
macro,Py_tp_getset,3.2,,
|
||||
macro,Py_tp_hash,3.2,,
|
||||
macro,Py_tp_init,3.2,,
|
||||
macro,Py_tp_is_gc,3.2,,
|
||||
macro,Py_tp_iter,3.2,,
|
||||
macro,Py_tp_iternext,3.2,,
|
||||
macro,Py_tp_members,3.2,,
|
||||
macro,Py_tp_methods,3.2,,
|
||||
macro,Py_tp_new,3.2,,
|
||||
macro,Py_tp_repr,3.2,,
|
||||
macro,Py_tp_richcompare,3.2,,
|
||||
macro,Py_tp_setattr,3.2,,
|
||||
macro,Py_tp_setattro,3.2,,
|
||||
macro,Py_tp_str,3.2,,
|
||||
macro,Py_tp_token,3.14,,
|
||||
macro,Py_tp_traverse,3.2,,
|
||||
macro,Py_tp_vectorcall,3.14,,
|
||||
type,Py_uintptr_t,3.2,,
|
||||
type,allocfunc,3.2,,
|
||||
type,binaryfunc,3.2,,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,7 @@
|
|||
Pending removal in Python 3.20
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* :c:func:`!_PyObject_CallMethodId`, :c:func:`!_PyObject_GetAttrId` and
|
||||
:c:func:`!_PyUnicode_FromId` are deprecated since 3.15 and will be removed in
|
||||
3.20. Instead, use :c:func:`PyUnicode_InternFromString()` and cache the result in
|
||||
the module state, then call :c:func:`PyObject_CallMethod` or
|
||||
:c:func:`PyObject_GetAttr`.
|
||||
(Contributed by Victor Stinner in :gh:`141049`.)
|
||||
|
||||
* The ``cval`` field in :c:type:`PyComplexObject` (:gh:`128813`).
|
||||
Use :c:func:`PyComplex_AsCComplex` and :c:func:`PyComplex_FromCComplex`
|
||||
to convert a Python complex number to/from the C :c:type:`Py_complex`
|
||||
representation.
|
||||
|
||||
* Macros :c:macro:`!Py_MATH_PIl` and :c:macro:`!Py_MATH_El`.
|
||||
|
|
|
|||
|
|
@ -38,3 +38,15 @@ APIs:
|
|||
* :meth:`!unittest.TestProgram.usageExit` (:gh:`67048`)
|
||||
* :class:`!webbrowser.MacOSX` (:gh:`86421`)
|
||||
* :class:`classmethod` descriptor chaining (:gh:`89519`)
|
||||
* :mod:`importlib.resources` deprecated methods:
|
||||
|
||||
* ``contents()``
|
||||
* ``is_resource()``
|
||||
* ``open_binary()``
|
||||
* ``open_text()``
|
||||
* ``path()``
|
||||
* ``read_binary()``
|
||||
* ``read_text()``
|
||||
|
||||
Use :func:`importlib.resources.files` instead. Refer to `importlib-resources: Migrating from Legacy
|
||||
<https://importlib-resources.readthedocs.io/en/latest/using.html#migrating-from-legacy>`_ (:gh:`106531`)
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ Pending removal in Python 3.15
|
|||
|
||||
* The import system:
|
||||
|
||||
* Setting ``__cached__`` on a module while
|
||||
* Setting :attr:`~module.__cached__` on a module while
|
||||
failing to set :attr:`__spec__.cached <importlib.machinery.ModuleSpec.cached>`
|
||||
is deprecated. In Python 3.15, ``__cached__`` will cease to be set or
|
||||
is deprecated. In Python 3.15, :attr:`!__cached__` will cease to be set or
|
||||
take into consideration by the import system or standard library. (:gh:`97879`)
|
||||
|
||||
* Setting :attr:`~module.__package__` on a module while
|
||||
|
|
@ -92,7 +92,7 @@ Pending removal in Python 3.15
|
|||
Use ``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``
|
||||
to create a TypedDict with zero field.
|
||||
|
||||
* The :func:`!typing.no_type_check_decorator` decorator function
|
||||
* The :func:`typing.no_type_check_decorator` decorator function
|
||||
has been deprecated since Python 3.13.
|
||||
After eight years in the :mod:`typing` module,
|
||||
it has yet to be supported by any major type checker.
|
||||
|
|
|
|||
|
|
@ -63,9 +63,9 @@ Pending removal in Python 3.16
|
|||
|
||||
* :mod:`logging`:
|
||||
|
||||
* Support for custom logging handlers with the *strm* argument is deprecated
|
||||
and scheduled for removal in Python 3.16. Define handlers with the *stream*
|
||||
argument instead. (Contributed by Mariusz Felisiak in :gh:`115032`.)
|
||||
Support for custom logging handlers with the *strm* argument is deprecated
|
||||
and scheduled for removal in Python 3.16. Define handlers with the *stream*
|
||||
argument instead. (Contributed by Mariusz Felisiak in :gh:`115032`.)
|
||||
|
||||
* :mod:`mimetypes`:
|
||||
|
||||
|
|
|
|||
|
|
@ -23,12 +23,6 @@ Pending removal in Python 3.17
|
|||
(Contributed by Shantanu Jain in :gh:`91896`.)
|
||||
|
||||
|
||||
* :mod:`encodings`:
|
||||
|
||||
- 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`)
|
||||
|
||||
* :mod:`typing`:
|
||||
|
||||
- Before Python 3.14, old-style unions were implemented using the private class
|
||||
|
|
|
|||
|
|
@ -1,17 +1,13 @@
|
|||
Pending removal in Python 3.20
|
||||
------------------------------
|
||||
|
||||
* 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.
|
||||
* The ``__version__`` attribute has been deprecated in these standard library
|
||||
modules and will be removed in Python 3.20.
|
||||
Use :py:data:`sys.version_info` instead.
|
||||
|
||||
- :mod:`argparse`
|
||||
- :mod:`csv`
|
||||
- :mod:`ctypes`
|
||||
- :mod:`!ctypes.macholib`
|
||||
- :mod:`decimal` (use :data:`decimal.SPEC_VERSION` instead)
|
||||
- :mod:`http.server`
|
||||
- :mod:`imaplib`
|
||||
- :mod:`ipaddress`
|
||||
- :mod:`json`
|
||||
- :mod:`logging` (``__date__`` also deprecated)
|
||||
|
|
@ -23,10 +19,5 @@ Pending removal in Python 3.20
|
|||
- :mod:`tabnanny`
|
||||
- :mod:`tkinter.font`
|
||||
- :mod:`tkinter.ttk`
|
||||
- :mod:`wsgiref.simple_server`
|
||||
- :mod:`xml.etree.ElementTree`
|
||||
- :mod:`!xml.sax.expatreader`
|
||||
- :mod:`xml.sax.handler`
|
||||
- :mod:`zlib`
|
||||
|
||||
(Contributed by Hugo van Kemenade and Stan Ulbrych in :gh:`76007`.)
|
||||
(Contributed by Hugo van Kemenade in :gh:`76007`.)
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ although there is currently no date scheduled for their removal.
|
|||
* :mod:`mailbox`: Use of StringIO input and text mode is deprecated, use
|
||||
BytesIO and binary mode instead.
|
||||
|
||||
* :mod:`os`: Calling :func:`os.register_at_fork` in a multi-threaded process.
|
||||
* :mod:`os`: Calling :func:`os.register_at_fork` in multi-threaded process.
|
||||
|
||||
* :class:`!pydoc.ErrorDuringImport`: A tuple value for *exc_info* parameter is
|
||||
deprecated, use an exception instance.
|
||||
|
|
|
|||
|
|
@ -3,20 +3,154 @@
|
|||
|
||||
.. _extending-intro:
|
||||
|
||||
********************************
|
||||
Using the C API: Assorted topics
|
||||
********************************
|
||||
******************************
|
||||
Extending Python with C or C++
|
||||
******************************
|
||||
|
||||
The :ref:`tutorial <first-extension-module>` walked you through
|
||||
creating a C API extension module, but left many areas unexplained.
|
||||
This document looks at several concepts that you'll need to learn
|
||||
in order to write more complex extensions.
|
||||
It is quite easy to add new built-in modules to Python, if you know how to
|
||||
program in C. Such :dfn:`extension modules` can do two things that can't be
|
||||
done directly in Python: they can implement new built-in object types, and they
|
||||
can call C library functions and system calls.
|
||||
|
||||
To support extensions, the Python API (Application Programmers Interface)
|
||||
defines a set of functions, macros and variables that provide access to most
|
||||
aspects of the Python run-time system. The Python API is incorporated in a C
|
||||
source file by including the header ``"Python.h"``.
|
||||
|
||||
The compilation of an extension module depends on its intended use as well as on
|
||||
your system setup; details are given in later chapters.
|
||||
|
||||
.. note::
|
||||
|
||||
The C extension interface is specific to CPython, and extension modules do
|
||||
not work on other Python implementations. In many cases, it is possible to
|
||||
avoid writing C extensions and preserve portability to other implementations.
|
||||
For example, if your use case is calling C library functions or system calls,
|
||||
you should consider using the :mod:`ctypes` module or the `cffi
|
||||
<https://cffi.readthedocs.io/>`_ library rather than writing
|
||||
custom C code.
|
||||
These modules let you write Python code to interface with C code and are more
|
||||
portable between implementations of Python than writing and compiling a C
|
||||
extension module.
|
||||
|
||||
|
||||
.. _extending-simpleexample:
|
||||
|
||||
A Simple Example
|
||||
================
|
||||
|
||||
Let's create an extension module called ``spam`` (the favorite food of Monty
|
||||
Python fans...) and let's say we want to create a Python interface to the C
|
||||
library function :c:func:`system` [#]_. This function takes a null-terminated
|
||||
character string as argument and returns an integer. We want this function to
|
||||
be callable from Python as follows:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import spam
|
||||
>>> status = spam.system("ls -l")
|
||||
|
||||
Begin by creating a file :file:`spammodule.c`. (Historically, if a module is
|
||||
called ``spam``, the C file containing its implementation is called
|
||||
:file:`spammodule.c`; if the module name is very long, like ``spammify``, the
|
||||
module name can be just :file:`spammify.c`.)
|
||||
|
||||
The first two lines of our file can be::
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
|
||||
which pulls in the Python API (you can add a comment describing the purpose of
|
||||
the module and a copyright notice if you like).
|
||||
|
||||
.. note::
|
||||
|
||||
Since Python may define some pre-processor definitions which affect the standard
|
||||
headers on some systems, you *must* include :file:`Python.h` before any standard
|
||||
headers are included.
|
||||
|
||||
``#define PY_SSIZE_T_CLEAN`` was used to indicate that ``Py_ssize_t`` should be
|
||||
used in some APIs instead of ``int``.
|
||||
It is not necessary since Python 3.13, but we keep it here for backward compatibility.
|
||||
See :ref:`arg-parsing-string-and-buffers` for a description of this macro.
|
||||
|
||||
All user-visible symbols defined by :file:`Python.h` have a prefix of ``Py`` or
|
||||
``PY``, except those defined in standard header files.
|
||||
|
||||
.. tip::
|
||||
|
||||
For backward compatibility, :file:`Python.h` includes several standard header files.
|
||||
C extensions should include the standard headers that they use,
|
||||
and should not rely on these implicit includes.
|
||||
If using the limited C API version 3.13 or newer, the implicit includes are:
|
||||
|
||||
* ``<assert.h>``
|
||||
* ``<intrin.h>`` (on Windows)
|
||||
* ``<inttypes.h>``
|
||||
* ``<limits.h>``
|
||||
* ``<math.h>``
|
||||
* ``<stdarg.h>``
|
||||
* ``<wchar.h>``
|
||||
* ``<sys/types.h>`` (if present)
|
||||
|
||||
If :c:macro:`Py_LIMITED_API` is not defined, or is set to version 3.12 or older,
|
||||
the headers below are also included:
|
||||
|
||||
* ``<ctype.h>``
|
||||
* ``<unistd.h>`` (on POSIX)
|
||||
|
||||
If :c:macro:`Py_LIMITED_API` is not defined, or is set to version 3.10 or older,
|
||||
the headers below are also included:
|
||||
|
||||
* ``<errno.h>``
|
||||
* ``<stdio.h>``
|
||||
* ``<stdlib.h>``
|
||||
* ``<string.h>``
|
||||
|
||||
The next thing we add to our module file is the C function that will be called
|
||||
when the Python expression ``spam.system(string)`` is evaluated (we'll see
|
||||
shortly how it ends up being called)::
|
||||
|
||||
static PyObject *
|
||||
spam_system(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char *command;
|
||||
int sts;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &command))
|
||||
return NULL;
|
||||
sts = system(command);
|
||||
return PyLong_FromLong(sts);
|
||||
}
|
||||
|
||||
There is a straightforward translation from the argument list in Python (for
|
||||
example, the single expression ``"ls -l"``) to the arguments passed to the C
|
||||
function. The C function always has two arguments, conventionally named *self*
|
||||
and *args*.
|
||||
|
||||
The *self* argument points to the module object for module-level functions;
|
||||
for a method it would point to the object instance.
|
||||
|
||||
The *args* argument will be a pointer to a Python tuple object containing the
|
||||
arguments. Each item of the tuple corresponds to an argument in the call's
|
||||
argument list. The arguments are Python objects --- in order to do anything
|
||||
with them in our C function we have to convert them to C values. The function
|
||||
:c:func:`PyArg_ParseTuple` in the Python API checks the argument types and
|
||||
converts them to C values. It uses a template string to determine the required
|
||||
types of the arguments as well as the types of the C variables into which to
|
||||
store the converted values. More about this later.
|
||||
|
||||
:c:func:`PyArg_ParseTuple` returns true (nonzero) if all arguments have the right
|
||||
type and its components have been stored in the variables whose addresses are
|
||||
passed. It returns false (zero) if an invalid argument list was passed. In the
|
||||
latter case it also raises an appropriate exception so the calling function can
|
||||
return ``NULL`` immediately (as we saw in the example).
|
||||
|
||||
|
||||
.. _extending-errors:
|
||||
|
||||
Errors and Exceptions
|
||||
=====================
|
||||
Intermezzo: Errors and Exceptions
|
||||
=================================
|
||||
|
||||
An important convention throughout the Python interpreter is the following: when
|
||||
a function fails, it should set an exception condition and return an error value
|
||||
|
|
@ -187,14 +321,194 @@ call to :c:func:`PyErr_SetString` as shown below::
|
|||
}
|
||||
|
||||
|
||||
.. _backtoexample:
|
||||
|
||||
Back to the Example
|
||||
===================
|
||||
|
||||
Going back to our example function, you should now be able to understand this
|
||||
statement::
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &command))
|
||||
return NULL;
|
||||
|
||||
It returns ``NULL`` (the error indicator for functions returning object pointers)
|
||||
if an error is detected in the argument list, relying on the exception set by
|
||||
:c:func:`PyArg_ParseTuple`. Otherwise the string value of the argument has been
|
||||
copied to the local variable :c:data:`!command`. This is a pointer assignment and
|
||||
you are not supposed to modify the string to which it points (so in Standard C,
|
||||
the variable :c:data:`!command` should properly be declared as ``const char
|
||||
*command``).
|
||||
|
||||
The next statement is a call to the Unix function :c:func:`system`, passing it
|
||||
the string we just got from :c:func:`PyArg_ParseTuple`::
|
||||
|
||||
sts = system(command);
|
||||
|
||||
Our :func:`!spam.system` function must return the value of :c:data:`!sts` as a
|
||||
Python object. This is done using the function :c:func:`PyLong_FromLong`. ::
|
||||
|
||||
return PyLong_FromLong(sts);
|
||||
|
||||
In this case, it will return an integer object. (Yes, even integers are objects
|
||||
on the heap in Python!)
|
||||
|
||||
If you have a C function that returns no useful argument (a function returning
|
||||
:c:expr:`void`), the corresponding Python function must return ``None``. You
|
||||
need this idiom to do so (which is implemented by the :c:macro:`Py_RETURN_NONE`
|
||||
macro)::
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
|
||||
:c:data:`Py_None` is the C name for the special Python object ``None``. It is a
|
||||
genuine Python object rather than a ``NULL`` pointer, which means "error" in most
|
||||
contexts, as we have seen.
|
||||
|
||||
|
||||
.. _methodtable:
|
||||
|
||||
The Module's Method Table and Initialization Function
|
||||
=====================================================
|
||||
|
||||
I promised to show how :c:func:`!spam_system` is called from Python programs.
|
||||
First, we need to list its name and address in a "method table"::
|
||||
|
||||
static PyMethodDef spam_methods[] = {
|
||||
...
|
||||
{"system", spam_system, METH_VARARGS,
|
||||
"Execute a shell command."},
|
||||
...
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
Note the third entry (``METH_VARARGS``). This is a flag telling the interpreter
|
||||
the calling convention to be used for the C function. It should normally always
|
||||
be ``METH_VARARGS`` or ``METH_VARARGS | METH_KEYWORDS``; a value of ``0`` means
|
||||
that an obsolete variant of :c:func:`PyArg_ParseTuple` is used.
|
||||
|
||||
When using only ``METH_VARARGS``, the function should expect the Python-level
|
||||
parameters to be passed in as a tuple acceptable for parsing via
|
||||
:c:func:`PyArg_ParseTuple`; more information on this function is provided below.
|
||||
|
||||
The :c:macro:`METH_KEYWORDS` bit may be set in the third field if keyword
|
||||
arguments should be passed to the function. In this case, the C function should
|
||||
accept a third ``PyObject *`` parameter which will be a dictionary of keywords.
|
||||
Use :c:func:`PyArg_ParseTupleAndKeywords` to parse the arguments to such a
|
||||
function.
|
||||
|
||||
The method table must be referenced in the module definition structure::
|
||||
|
||||
static struct PyModuleDef spam_module = {
|
||||
...
|
||||
.m_methods = spam_methods,
|
||||
...
|
||||
};
|
||||
|
||||
This structure, in turn, must be passed to the interpreter in the module's
|
||||
initialization function. The initialization function must be named
|
||||
:c:func:`!PyInit_name`, where *name* is the name of the module, and should be the
|
||||
only non-\ ``static`` item defined in the module file::
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_spam(void)
|
||||
{
|
||||
return PyModuleDef_Init(&spam_module);
|
||||
}
|
||||
|
||||
Note that :c:macro:`PyMODINIT_FUNC` declares the function as ``PyObject *`` return type,
|
||||
declares any special linkage declarations required by the platform, and for C++
|
||||
declares the function as ``extern "C"``.
|
||||
|
||||
:c:func:`!PyInit_spam` is called when each interpreter imports its module
|
||||
:mod:`!spam` for the first time. (See below for comments about embedding Python.)
|
||||
A pointer to the module definition must be returned via :c:func:`PyModuleDef_Init`,
|
||||
so that the import machinery can create the module and store it in ``sys.modules``.
|
||||
|
||||
When embedding Python, the :c:func:`!PyInit_spam` function is not called
|
||||
automatically unless there's an entry in the :c:data:`!PyImport_Inittab` table.
|
||||
To add the module to the initialization table, use :c:func:`PyImport_AppendInittab`,
|
||||
optionally followed by an import of the module::
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
PyStatus status;
|
||||
PyConfig config;
|
||||
PyConfig_InitPythonConfig(&config);
|
||||
|
||||
/* Add a built-in module, before Py_Initialize */
|
||||
if (PyImport_AppendInittab("spam", PyInit_spam) == -1) {
|
||||
fprintf(stderr, "Error: could not extend in-built modules table\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Pass argv[0] to the Python interpreter */
|
||||
status = PyConfig_SetBytesString(&config, &config.program_name, argv[0]);
|
||||
if (PyStatus_Exception(status)) {
|
||||
goto exception;
|
||||
}
|
||||
|
||||
/* Initialize the Python interpreter. Required.
|
||||
If this step fails, it will be a fatal error. */
|
||||
status = Py_InitializeFromConfig(&config);
|
||||
if (PyStatus_Exception(status)) {
|
||||
goto exception;
|
||||
}
|
||||
PyConfig_Clear(&config);
|
||||
|
||||
/* Optionally import the module; alternatively,
|
||||
import can be deferred until the embedded script
|
||||
imports it. */
|
||||
PyObject *pmodule = PyImport_ImportModule("spam");
|
||||
if (!pmodule) {
|
||||
PyErr_Print();
|
||||
fprintf(stderr, "Error: could not import module 'spam'\n");
|
||||
}
|
||||
|
||||
// ... use Python C API here ...
|
||||
|
||||
return 0;
|
||||
|
||||
exception:
|
||||
PyConfig_Clear(&config);
|
||||
Py_ExitStatusException(status);
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
If you declare a global variable or a local static one, the module may
|
||||
experience unintended side-effects on re-initialisation, for example when
|
||||
removing entries from ``sys.modules`` or importing compiled modules into
|
||||
multiple interpreters within a process
|
||||
(or following a :c:func:`fork` without an intervening :c:func:`exec`).
|
||||
If module state is not yet fully :ref:`isolated <isolating-extensions-howto>`,
|
||||
authors should consider marking the module as having no support for subinterpreters
|
||||
(via :c:macro:`Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED`).
|
||||
|
||||
A more substantial example module is included in the Python source distribution
|
||||
as :file:`Modules/xxlimited.c`. This file may be used as a template or simply
|
||||
read as an example.
|
||||
|
||||
|
||||
.. _compilation:
|
||||
|
||||
Embedding an extension
|
||||
======================
|
||||
Compilation and Linkage
|
||||
=======================
|
||||
|
||||
If you want to make your module a permanent
|
||||
There are two more things to do before you can use your new extension: compiling
|
||||
and linking it with the Python system. If you use dynamic loading, the details
|
||||
may depend on the style of dynamic loading your system uses; see the chapters
|
||||
about building extension modules (chapter :ref:`building`) and additional
|
||||
information that pertains only to building on Windows (chapter
|
||||
:ref:`building-on-windows`) for more information about this.
|
||||
|
||||
If you can't use dynamic loading, or if you want to make your module a permanent
|
||||
part of the Python interpreter, you will have to change the configuration setup
|
||||
and rebuild the interpreter. On Unix, place
|
||||
and rebuild the interpreter. Luckily, this is very simple on Unix: just place
|
||||
your file (:file:`spammodule.c` for example) in the :file:`Modules/` directory
|
||||
of an unpacked source distribution, add a line to the file
|
||||
:file:`Modules/Setup.local` describing your file:
|
||||
|
|
@ -222,7 +536,7 @@ on the line in the configuration file as well, for instance:
|
|||
Calling Python Functions from C
|
||||
===============================
|
||||
|
||||
The tutorial concentrated on making C functions callable from Python. The
|
||||
So far we have concentrated on making C functions callable from Python. The
|
||||
reverse is also useful: calling Python functions from C. This is especially the
|
||||
case for libraries that support so-called "callback" functions. If a C
|
||||
interface makes use of callbacks, the equivalent Python often needs to provide a
|
||||
|
|
@ -267,7 +581,7 @@ be part of a module definition::
|
|||
}
|
||||
|
||||
This function must be registered with the interpreter using the
|
||||
:c:macro:`METH_VARARGS` flag in :c:type:`PyMethodDef.ml_flags`. The
|
||||
:c:macro:`METH_VARARGS` flag; this is described in section :ref:`methodtable`. The
|
||||
:c:func:`PyArg_ParseTuple` function and its arguments are documented in section
|
||||
:ref:`parsetuple`.
|
||||
|
||||
|
|
@ -362,21 +676,14 @@ the above example, we use :c:func:`Py_BuildValue` to construct the dictionary. :
|
|||
Py_DECREF(result);
|
||||
|
||||
|
||||
.. index:: single: PyArg_ParseTuple (C function)
|
||||
|
||||
.. _parsetuple:
|
||||
|
||||
Extracting Parameters in Extension Functions
|
||||
============================================
|
||||
|
||||
The :ref:`tutorial <first-extension-module>` uses a ":c:data:`METH_O`"
|
||||
function, which is limited to a single Python argument.
|
||||
If you want more, you can use :c:data:`METH_VARARGS` instead.
|
||||
With this flag, the C function will receive a :py:class:`tuple` of arguments
|
||||
instead of a single object.
|
||||
.. index:: single: PyArg_ParseTuple (C function)
|
||||
|
||||
For unpacking the tuple, CPython provides the :c:func:`PyArg_ParseTuple`
|
||||
function, declared as follows::
|
||||
The :c:func:`PyArg_ParseTuple` function is declared as follows::
|
||||
|
||||
int PyArg_ParseTuple(PyObject *arg, const char *format, ...);
|
||||
|
||||
|
|
@ -386,19 +693,6 @@ whose syntax is explained in :ref:`arg-parsing` in the Python/C API Reference
|
|||
Manual. The remaining arguments must be addresses of variables whose type is
|
||||
determined by the format string.
|
||||
|
||||
For example, to receive a single Python :py:class:`str` object and turn it
|
||||
into a C buffer, you would use ``"s"`` as the format string::
|
||||
|
||||
const char *command;
|
||||
if (!PyArg_ParseTuple(args, "s", &command)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
If an error is detected in the argument list, :c:func:`!PyArg_ParseTuple`
|
||||
returns ``NULL`` (the error indicator for functions returning object pointers);
|
||||
your function may return ``NULL``, relying on the exception set by
|
||||
:c:func:`PyArg_ParseTuple`.
|
||||
|
||||
Note that while :c:func:`PyArg_ParseTuple` checks that the Python arguments have
|
||||
the required types, it cannot check the validity of the addresses of C variables
|
||||
passed to the call: if you make mistakes there, your code will probably crash or
|
||||
|
|
@ -409,6 +703,7 @@ Note that any Python object references which are provided to the caller are
|
|||
|
||||
Some example calls::
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
|
||||
::
|
||||
|
|
@ -478,17 +773,6 @@ Some example calls::
|
|||
Keyword Parameters for Extension Functions
|
||||
==========================================
|
||||
|
||||
If you also want your function to accept
|
||||
:term:`keyword arguments <keyword argument>`, use the :c:data:`METH_KEYWORDS`
|
||||
flag in combination with :c:data:`METH_VARARGS`.
|
||||
(:c:data:`!METH_KEYWORDS` can also be used with other flags; see its
|
||||
documentation for the allowed combinations.)
|
||||
|
||||
In this case, the C function should accept a third ``PyObject *`` parameter
|
||||
which will be a dictionary of keywords.
|
||||
Use :c:func:`PyArg_ParseTupleAndKeywords` to parse the arguments to such a
|
||||
function.
|
||||
|
||||
.. index:: single: PyArg_ParseTupleAndKeywords (C function)
|
||||
|
||||
The :c:func:`PyArg_ParseTupleAndKeywords` function is declared as follows::
|
||||
|
|
@ -549,6 +833,19 @@ Philbrick (philbrick@hks.com)::
|
|||
{NULL, NULL, 0, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static struct PyModuleDef keywdarg_module = {
|
||||
.m_base = PyModuleDef_HEAD_INIT,
|
||||
.m_name = "keywdarg",
|
||||
.m_size = 0,
|
||||
.m_methods = keywdarg_methods,
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_keywdarg(void)
|
||||
{
|
||||
return PyModuleDef_Init(&keywdarg_module);
|
||||
}
|
||||
|
||||
|
||||
.. _buildvalue:
|
||||
|
||||
|
|
@ -689,11 +986,11 @@ needed. Ownership of a reference can be transferred. There are three ways to
|
|||
dispose of an owned reference: pass it on, store it, or call :c:func:`Py_DECREF`.
|
||||
Forgetting to dispose of an owned reference creates a memory leak.
|
||||
|
||||
It is also possible to :dfn:`borrow` [#borrow]_ a reference to an object. The
|
||||
It is also possible to :dfn:`borrow` [#]_ a reference to an object. The
|
||||
borrower of a reference should not call :c:func:`Py_DECREF`. The borrower must
|
||||
not hold on to the object longer than the owner from which it was borrowed.
|
||||
Using a borrowed reference after the owner has disposed of it risks using freed
|
||||
memory and should be avoided completely [#dont-check-refcount]_.
|
||||
memory and should be avoided completely [#]_.
|
||||
|
||||
The advantage of borrowing over owning a reference is that you don't need to
|
||||
take care of disposing of the reference on all possible paths through the code
|
||||
|
|
@ -872,7 +1169,7 @@ checking.
|
|||
|
||||
The C function calling mechanism guarantees that the argument list passed to C
|
||||
functions (``args`` in the examples) is never ``NULL`` --- in fact it guarantees
|
||||
that it is always a tuple [#old-calling-convention]_.
|
||||
that it is always a tuple [#]_.
|
||||
|
||||
It is a severe error to ever let a ``NULL`` pointer "escape" to the Python user.
|
||||
|
||||
|
|
@ -929,8 +1226,8 @@ the module whose functions one wishes to call might not have been loaded yet!
|
|||
Portability therefore requires not to make any assumptions about symbol
|
||||
visibility. This means that all symbols in extension modules should be declared
|
||||
``static``, except for the module's initialization function, in order to
|
||||
avoid name clashes with other extension modules. And it means that symbols
|
||||
that *should* be accessible from
|
||||
avoid name clashes with other extension modules (as discussed in section
|
||||
:ref:`methodtable`). And it means that symbols that *should* be accessible from
|
||||
other extension modules must be exported in a different way.
|
||||
|
||||
Python provides a special mechanism to pass C-level information (pointers) from
|
||||
|
|
@ -972,9 +1269,8 @@ file corresponding to the module provides a macro that takes care of importing
|
|||
the module and retrieving its C API pointers; client modules only have to call
|
||||
this macro before accessing the C API.
|
||||
|
||||
The exporting module is a modification of the :mod:`!spam` module from the
|
||||
:ref:`tutorial <first-extension-module>`.
|
||||
The function :func:`!spam.system` does not call
|
||||
The exporting module is a modification of the :mod:`!spam` module from section
|
||||
:ref:`extending-simpleexample`. The function :func:`!spam.system` does not call
|
||||
the C library function :c:func:`system` directly, but a function
|
||||
:c:func:`!PySpam_System`, which would of course do something more complicated in
|
||||
reality (such as adding "spam" to every command). This function
|
||||
|
|
@ -1116,14 +1412,15 @@ code distribution).
|
|||
|
||||
.. rubric:: Footnotes
|
||||
|
||||
.. [#borrow] The metaphor of "borrowing" a reference is not completely correct:
|
||||
the owner still has a copy of the reference.
|
||||
.. [#] An interface for this function already exists in the standard module :mod:`os`
|
||||
--- it was chosen as a simple and straightforward example.
|
||||
|
||||
.. [#dont-check-refcount] Checking that the reference count is at least 1
|
||||
**does not work** --- the
|
||||
.. [#] The metaphor of "borrowing" a reference is not completely correct: the owner
|
||||
still has a copy of the reference.
|
||||
|
||||
.. [#] Checking that the reference count is at least 1 **does not work** --- the
|
||||
reference count itself could be in freed memory and may thus be reused for
|
||||
another object!
|
||||
|
||||
.. [#old-calling-convention] These guarantees don't hold when you use the
|
||||
"old" style calling convention ---
|
||||
.. [#] These guarantees don't hold when you use the "old" style calling convention ---
|
||||
this is still found in much existing code.
|
||||
|
|
|
|||
|
|
@ -1,667 +0,0 @@
|
|||
.. highlight:: c
|
||||
|
||||
|
||||
.. _extending-simpleexample:
|
||||
.. _first-extension-module:
|
||||
|
||||
*********************************
|
||||
Your first C API extension module
|
||||
*********************************
|
||||
|
||||
This tutorial will take you through creating a simple
|
||||
Python extension module written in C or C++.
|
||||
|
||||
We will use the low-level Python C API directly.
|
||||
For easier ways to create extension modules, see
|
||||
the :ref:`recommended third party tools <c-api-tools>`.
|
||||
|
||||
The tutorial assumes basic knowledge about Python: you should be able to
|
||||
define functions in Python code before starting to write them in C.
|
||||
See :ref:`tutorial-index` for an introduction to Python itself.
|
||||
|
||||
The tutorial should be approachable for anyone who can write a basic C library.
|
||||
While we will mention several concepts that a C beginner would not be expected
|
||||
to know, like ``static`` functions or linkage declarations, understanding these
|
||||
is not necessary for success.
|
||||
|
||||
We will focus on giving you a "feel" of what Python's C API is like.
|
||||
It will not teach you important concepts, like error handling
|
||||
and reference counting, which are covered in later chapters.
|
||||
|
||||
We will assume that you use a Unix-like system (including macOS and
|
||||
Linux), or Windows.
|
||||
On other systems, you might need to adjust some details -- for example,
|
||||
a system command name.
|
||||
|
||||
You need to have a suitable C compiler and Python development headers installed.
|
||||
On Linux, headers are often in a package like ``python3-dev``
|
||||
or ``python3-devel``.
|
||||
|
||||
You need to be able to install Python packages.
|
||||
This tutorial uses `pip <https://pip.pypa.io/>`__ (``pip install``), but you
|
||||
can substitute any tool that can build and install ``pyproject.toml``-based
|
||||
projects, like `uv <https://docs.astral.sh/uv/>`_ (``uv pip install``).
|
||||
Preferably, have a :ref:`virtual environment <venv-def>` activated.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
This tutorial uses APIs that were added in CPython 3.15.
|
||||
To create an extension that's compatible with earlier versions of CPython,
|
||||
please follow an earlier version of this documentation.
|
||||
|
||||
This tutorial uses C syntax added in C11 and C++20.
|
||||
If your extension needs to be compatible with earlier standards,
|
||||
please follow tutorials in documentation for Python 3.14 or below.
|
||||
|
||||
|
||||
What we'll do
|
||||
=============
|
||||
|
||||
Let's create an extension module called ``spam`` [#why-spam]_,
|
||||
which will include a Python interface to the C
|
||||
standard library function :c:func:`system`.
|
||||
This function is defined in ``stdlib.h``.
|
||||
It takes a C string as argument, runs the argument as a system
|
||||
command, and returns a result value as an integer.
|
||||
A manual page for :c:func:`system` might summarize it this way::
|
||||
|
||||
#include <stdlib.h>
|
||||
int system(const char *command);
|
||||
|
||||
Note that like many functions in the C standard library,
|
||||
this function is already exposed in Python.
|
||||
In production, use :py:func:`os.system` or :py:func:`subprocess.run`
|
||||
rather than the module you'll write here.
|
||||
|
||||
We want this function to be callable from Python as follows:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import spam
|
||||
>>> status = spam.system("whoami")
|
||||
User Name
|
||||
>>> status
|
||||
0
|
||||
|
||||
.. note::
|
||||
|
||||
The system command ``whoami`` prints out your username.
|
||||
It's useful in tutorials like this one because it has the same name on
|
||||
both Unix and Windows.
|
||||
|
||||
|
||||
Start with the headers
|
||||
======================
|
||||
|
||||
Begin by creating a directory for this tutorial, and switching to it
|
||||
on the command line.
|
||||
Then, create a file named :file:`spammodule.c` in your directory.
|
||||
[#why-spammodule]_
|
||||
|
||||
In this file, we'll include two headers: :file:`Python.h` to pull in
|
||||
all declarations of the Python C API, and :file:`stdlib.h` for the
|
||||
:c:func:`system` function. [#stdlib-h]_
|
||||
|
||||
Add the following lines to :file:`spammodule.c`:
|
||||
|
||||
.. literalinclude:: ../includes/capi-extension/spammodule-01.c
|
||||
:start-at: <Python.h>
|
||||
:end-at: <stdlib.h>
|
||||
|
||||
Be sure to put :file:`stdlib.h`, and any other standard library includes,
|
||||
*after* :file:`Python.h`.
|
||||
On some systems, Python may define some pre-processor definitions
|
||||
that affect the standard headers.
|
||||
|
||||
|
||||
Running your build tool
|
||||
=======================
|
||||
|
||||
With only the includes in place, your extension won't do anything.
|
||||
Still, it's a good time to compile it and try to import it.
|
||||
This will ensure that your build tool works, so that you can make
|
||||
and test incremental changes as you follow the rest of the text.
|
||||
|
||||
CPython itself does not come with a tool to build extension modules;
|
||||
it is recommended to use a third-party project for this.
|
||||
In this tutorial, we'll use `meson-python`_.
|
||||
(If you want to use another one, see :ref:`first-extension-other-tools`.)
|
||||
|
||||
.. at the time of writing, meson-python has the least overhead for a
|
||||
simple extension using PyModExport.
|
||||
Change this if another tool makes things easier.
|
||||
|
||||
``meson-python`` requires defining a "project" using two extra files.
|
||||
|
||||
First, add ``pyproject.toml`` with these contents:
|
||||
|
||||
.. code-block:: toml
|
||||
|
||||
[build-system]
|
||||
build-backend = 'mesonpy'
|
||||
requires = ['meson-python']
|
||||
|
||||
[project]
|
||||
# Placeholder project information
|
||||
# (change this before distributing the module)
|
||||
name = 'sampleproject'
|
||||
version = '0'
|
||||
|
||||
Then, create ``meson.build`` containing the following:
|
||||
|
||||
.. code-block:: meson
|
||||
|
||||
project('sampleproject', 'c')
|
||||
|
||||
py = import('python').find_installation(pure: false)
|
||||
|
||||
py.extension_module(
|
||||
'spam', # name of the importable Python module
|
||||
'spammodule.c', # the C source file
|
||||
install: true,
|
||||
)
|
||||
|
||||
.. note::
|
||||
|
||||
See `meson-python documentation <meson-python>`_ for details on
|
||||
configuration.
|
||||
|
||||
Now, build install the *project in the current directory* (``.``) via ``pip``:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
python -m pip install .
|
||||
|
||||
.. tip::
|
||||
|
||||
If you don't have ``pip`` installed, run ``python -m ensurepip``,
|
||||
preferably in a :ref:`virtual environment <venv-def>`.
|
||||
(Or, if you prefer another tool that can build and install
|
||||
``pyproject.toml``-based projects, use that.)
|
||||
|
||||
.. _meson-python: https://mesonbuild.com/meson-python/
|
||||
.. _virtual environment: https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/#create-and-use-virtual-environments
|
||||
|
||||
Note that you will need to run this command again every time you change your
|
||||
extension.
|
||||
Unlike Python, C has an explicit compilation step.
|
||||
|
||||
When your extension is compiled and installed, start Python and try to
|
||||
import it.
|
||||
This should fail with the following exception:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import spam
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ImportError: dynamic module does not define module export function (PyModExport_spam or PyInit_spam)
|
||||
|
||||
|
||||
Module export hook
|
||||
==================
|
||||
|
||||
The exception you got when you tried to import the module told you that Python
|
||||
is looking for a "module export function", also known as a
|
||||
:ref:`module export hook <extension-export-hook>`.
|
||||
Let's define one.
|
||||
|
||||
First, add a prototype below the ``#include`` lines:
|
||||
|
||||
.. literalinclude:: ../includes/capi-extension/spammodule-01.c
|
||||
:start-after: /// Export hook prototype
|
||||
:end-before: ///
|
||||
|
||||
.. tip::
|
||||
The prototype is not strictly necessary, but some modern compilers emit
|
||||
warnings without it.
|
||||
It's generally better to add the prototype than to disable the warning.
|
||||
|
||||
The :c:macro:`PyMODEXPORT_FUNC` macro declares the function's
|
||||
return type, and adds any special linkage declarations needed
|
||||
to make the function visible and usable when CPython loads it.
|
||||
|
||||
After the prototype, add the function itself.
|
||||
For now, make it return ``NULL``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
PyMODEXPORT_FUNC
|
||||
PyModExport_spam(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Compile and load the module again.
|
||||
You should get a different error this time.
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import spam
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SystemError: module export hook for module 'spam' failed without setting an exception
|
||||
|
||||
Simply returning ``NULL`` is *not* correct behavior for an export hook,
|
||||
and CPython complains about it.
|
||||
That's good -- it means that CPython found the function!
|
||||
Let's now make it do something useful.
|
||||
|
||||
|
||||
The slot table
|
||||
==============
|
||||
|
||||
Rather than ``NULL``, the export hook should return the information needed to
|
||||
create a module.
|
||||
Let's start with the basics: the name and docstring.
|
||||
|
||||
The information should be defined in a ``static`` array of
|
||||
:c:type:`PyModuleDef_Slot` entries, which are essentially key-value pairs.
|
||||
Define this array just before your export hook:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static PyModuleDef_Slot spam_slots[] = {
|
||||
{Py_mod_name, "spam"},
|
||||
{Py_mod_doc, "A wonderful module with an example function"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
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.
|
||||
|
||||
Note the zero-filled sentinel entry at the end.
|
||||
If you forget it, you'll trigger undefined behavior.
|
||||
|
||||
The array is defined as ``static`` -- that is, not visible outside this ``.c`` file.
|
||||
This will be a common theme.
|
||||
CPython only needs to access the export hook; all global variables
|
||||
and all other functions should generally be ``static``, so that they don't
|
||||
clash with other extensions.
|
||||
|
||||
Return this array from your export hook instead of ``NULL``:
|
||||
|
||||
.. code-block:: c
|
||||
:emphasize-lines: 4
|
||||
|
||||
PyMODEXPORT_FUNC
|
||||
PyModExport_spam(void)
|
||||
{
|
||||
return spam_slots;
|
||||
}
|
||||
|
||||
Now, recompile and try it out:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import spam
|
||||
>>> print(spam)
|
||||
<module 'spam' from '/home/encukou/dev/cpython/spam.so'>
|
||||
|
||||
You have an extension module!
|
||||
Try ``help(spam)`` to see the docstring.
|
||||
|
||||
The next step will be adding a function.
|
||||
|
||||
|
||||
.. _backtoexample:
|
||||
|
||||
Exposing a function
|
||||
===================
|
||||
|
||||
To expose the :c:func:`system` C function directly to Python,
|
||||
we'll need to write a layer of glue code to convert arguments from Python
|
||||
objects to C values, and the C return value back to Python.
|
||||
|
||||
One of the simplest ways to write glue code is a ":c:data:`METH_O`" function,
|
||||
which takes two Python objects and returns one.
|
||||
All Python objects -- regardless of the Python type -- are represented in C
|
||||
as pointers to the :c:type:`PyObject` structure.
|
||||
|
||||
Add such a function above the slots array::
|
||||
|
||||
static PyObject *
|
||||
spam_system(PyObject *self, PyObject *arg)
|
||||
{
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
For now, we ignore the arguments, and use the :c:macro:`Py_RETURN_NONE`
|
||||
macro, which expands to a ``return`` statement that properly returns
|
||||
a Python :py:data:`None` object.
|
||||
|
||||
Recompile your extension to make sure you don't have syntax errors.
|
||||
We haven't yet added ``spam_system`` to the module, so you might get a
|
||||
warning that ``spam_system`` is unused.
|
||||
|
||||
.. _methodtable:
|
||||
|
||||
Method definitions
|
||||
------------------
|
||||
|
||||
To expose the C function to Python, you will need to provide several pieces of
|
||||
information in a structure called
|
||||
:c:type:`PyMethodDef` [#why-pymethoddef]_:
|
||||
|
||||
* ``ml_name``: the name of the Python function;
|
||||
* ``ml_doc``: a docstring;
|
||||
* ``ml_meth``: the C function to be called; and
|
||||
* ``ml_flags``: a set of flags describing details like how Python arguments are
|
||||
passed to the C function.
|
||||
We'll use :c:data:`METH_O` here -- the flag that matches our
|
||||
``spam_system`` function's signature.
|
||||
|
||||
Because modules typically create several functions, these definitions
|
||||
need to be collected in an array, with a zero-filled sentinel at the end.
|
||||
Add this array just below the ``spam_system`` function:
|
||||
|
||||
.. literalinclude:: ../includes/capi-extension/spammodule-01.c
|
||||
:start-after: /// Module method table
|
||||
:end-before: ///
|
||||
|
||||
As with module slots, a zero-filled sentinel marks the end of the array.
|
||||
|
||||
Next, we'll add the method to the module.
|
||||
Add a :c:data:`Py_mod_methods` slot to your :c:type:`PyMethodDef` array:
|
||||
|
||||
.. literalinclude:: ../includes/capi-extension/spammodule-01.c
|
||||
:start-after: /// Module slot table
|
||||
:end-before: ///
|
||||
:emphasize-lines: 5
|
||||
|
||||
Recompile your extension again, and test it.
|
||||
Be sure to restart the Python interpreter, so that ``import spam`` picks
|
||||
up the new version of the module.
|
||||
|
||||
You should now be able to call the function:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import spam
|
||||
>>> print(spam.system)
|
||||
<built-in function system>
|
||||
>>> print(spam.system('whoami'))
|
||||
None
|
||||
|
||||
Note that our ``spam.system`` does not yet run the ``whoami`` command;
|
||||
it only returns ``None``.
|
||||
|
||||
Check that the function accepts exactly one argument, as specified by
|
||||
the :c:data:`METH_O` flag:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> print(spam.system('too', 'many', 'arguments'))
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: spam.system() takes exactly one argument (3 given)
|
||||
|
||||
|
||||
Returning an integer
|
||||
====================
|
||||
|
||||
Now, let's take a look at the return value.
|
||||
Instead of ``None``, we'll want ``spam.system`` to return a number -- that is,
|
||||
a Python :py:type:`int` object.
|
||||
Eventually this will be the exit code of a system command,
|
||||
but let's start with a fixed value, say, ``3``.
|
||||
|
||||
The Python C API provides a function to create a Python :py:type:`int` object
|
||||
from a C ``int`` value: :c:func:`PyLong_FromLong`. [#why-pylongfromlong]_
|
||||
|
||||
To call it, replace the ``Py_RETURN_NONE`` with the following 3 lines:
|
||||
|
||||
.. this could be a one-liner, but we want to show the data types here
|
||||
|
||||
.. code-block:: c
|
||||
:emphasize-lines: 4-6
|
||||
|
||||
static PyObject *
|
||||
spam_system(PyObject *self, PyObject *arg)
|
||||
{
|
||||
int status = 3;
|
||||
PyObject *result = PyLong_FromLong(status);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Recompile, restart the Python interpreter again,
|
||||
and check that the function now returns 3:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import spam
|
||||
>>> spam.system('whoami')
|
||||
3
|
||||
|
||||
|
||||
Accepting a string
|
||||
==================
|
||||
|
||||
Finally, let's handle the function argument.
|
||||
|
||||
Our C function, :c:func:`!spam_system`, takes two arguments.
|
||||
The first one, ``PyObject *self``, will be set to the ``spam`` module
|
||||
object.
|
||||
This isn't useful in our case, so we'll ignore it.
|
||||
|
||||
The other one, ``PyObject *arg``, will be set to the object that the user
|
||||
passed from Python.
|
||||
We expect that it should be a Python string.
|
||||
In order to use the information in it, we will need
|
||||
to convert it to a C value -- in this case, a C string (``const char *``).
|
||||
|
||||
There's a slight type mismatch here: Python's :py:class:`str` objects store
|
||||
Unicode text, but C strings are arrays of bytes.
|
||||
So, we'll need to *encode* the data, and we'll use the UTF-8 encoding for it.
|
||||
(UTF-8 might not always be correct for system commands, but it's what
|
||||
:py:meth:`str.encode` uses by default,
|
||||
and the C API has special support for it.)
|
||||
|
||||
The function to encode a Python string into a UTF-8 buffer is named
|
||||
:c:func:`PyUnicode_AsUTF8` [#why-pyunicodeasutf8]_.
|
||||
Call it like this:
|
||||
|
||||
.. code-block:: c
|
||||
:emphasize-lines: 4
|
||||
|
||||
static PyObject *
|
||||
spam_system(PyObject *self, PyObject *arg)
|
||||
{
|
||||
const char *command = PyUnicode_AsUTF8(arg);
|
||||
int status = 3;
|
||||
PyObject *result = PyLong_FromLong(status);
|
||||
return result;
|
||||
}
|
||||
|
||||
If :c:func:`PyUnicode_AsUTF8` is successful, *command* will point to the
|
||||
resulting array of bytes.
|
||||
This buffer is managed by the *arg* object, which means we don't need to free
|
||||
it, but we must follow some rules:
|
||||
|
||||
* We should only use the buffer inside the ``spam_system`` function.
|
||||
When ``spam_system`` returns, *arg* and the buffer it manages might be
|
||||
garbage-collected.
|
||||
* We must not modify it. This is why we use ``const``.
|
||||
|
||||
If :c:func:`PyUnicode_AsUTF8` was *not* successful, it returns a ``NULL``
|
||||
pointer.
|
||||
When calling *any* Python C API, we always need to handle such error cases.
|
||||
The way to do this in general is left for later chapters of this documentation.
|
||||
For now, be assured that we are already handling errors from
|
||||
:c:func:`PyLong_FromLong` correctly.
|
||||
|
||||
For the :c:func:`PyUnicode_AsUTF8` call, the correct way to handle errors is
|
||||
returning ``NULL`` from ``spam_system``.
|
||||
Add an ``if`` block for this:
|
||||
|
||||
|
||||
.. code-block:: c
|
||||
:emphasize-lines: 5-7
|
||||
|
||||
static PyObject *
|
||||
spam_system(PyObject *self, PyObject *arg)
|
||||
{
|
||||
const char *command = PyUnicode_AsUTF8(arg);
|
||||
if (command == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
int status = 3;
|
||||
PyObject *result = PyLong_FromLong(status);
|
||||
return result;
|
||||
}
|
||||
|
||||
That's it for the setup.
|
||||
Now, all that is left is calling the C library function :c:func:`system` with
|
||||
the ``char *`` buffer, and using its result instead of the ``3``:
|
||||
|
||||
.. code-block:: c
|
||||
:emphasize-lines: 8
|
||||
|
||||
static PyObject *
|
||||
spam_system(PyObject *self, PyObject *arg)
|
||||
{
|
||||
const char *command = PyUnicode_AsUTF8(arg);
|
||||
if (command == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
int status = system(command);
|
||||
PyObject *result = PyLong_FromLong(status);
|
||||
return result;
|
||||
}
|
||||
|
||||
Compile your module, restart Python, and test.
|
||||
This time, you should see your username -- the output of the ``whoami``
|
||||
system command:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import spam
|
||||
>>> result = spam.system('whoami')
|
||||
User Name
|
||||
>>> result
|
||||
0
|
||||
|
||||
You might also want to test error cases:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import spam
|
||||
>>> result = spam.system('nonexistent-command')
|
||||
sh: line 1: nonexistent-command: command not found
|
||||
>>> result
|
||||
32512
|
||||
|
||||
>>> spam.system(3)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: bad argument type for built-in operation
|
||||
|
||||
|
||||
The result
|
||||
==========
|
||||
|
||||
|
||||
Congratulations!
|
||||
You have written a complete Python C API extension module,
|
||||
and completed this tutorial!
|
||||
|
||||
Here is the entire source file, for your convenience:
|
||||
|
||||
.. _extending-spammodule-source:
|
||||
|
||||
.. literalinclude:: ../includes/capi-extension/spammodule-01.c
|
||||
:start-at: ///
|
||||
|
||||
|
||||
.. _first-extension-other-tools:
|
||||
|
||||
Appendix: Other build tools
|
||||
===========================
|
||||
|
||||
You should be able to follow this tutorial -- except the
|
||||
*Running your build tool* section itself -- with a build tool other
|
||||
than ``meson-python``.
|
||||
|
||||
The Python Packaging User Guide has a `list of recommended tools <https://packaging.python.org/en/latest/guides/tool-recommendations/#build-backends-for-extension-modules>`_;
|
||||
be sure to choose one for the C language.
|
||||
|
||||
|
||||
Workaround for missing PyInit function
|
||||
--------------------------------------
|
||||
|
||||
If your build tool output complains about missing ``PyInit_spam``,
|
||||
add the following function to your module for now:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
// A workaround
|
||||
void *PyInit_spam(void) { return NULL; }
|
||||
|
||||
This is a shim for an old-style :ref:`initialization function <extension-export-hook>`,
|
||||
which was required in extension modules for CPython 3.14 and below.
|
||||
Current CPython does not need it, but some build tools may still assume that
|
||||
all extension modules need to define it.
|
||||
|
||||
If you use this workaround, you will get the exception
|
||||
``SystemError: initialization of spam failed without raising an exception``
|
||||
instead of
|
||||
``ImportError: dynamic module does not define module export function``.
|
||||
|
||||
|
||||
Compiling directly
|
||||
------------------
|
||||
|
||||
Using a third-party build tool is heavily recommended,
|
||||
as it will take care of various details of your platform and Python
|
||||
installation, of naming the resulting extension, and, later, of distributing
|
||||
your work.
|
||||
|
||||
If you are building an extension for as *specific* system, or for yourself
|
||||
only, you might instead want to run your compiler directly.
|
||||
The way to do this is system-specific; be prepared for issues you will need
|
||||
to solve yourself.
|
||||
|
||||
Linux
|
||||
^^^^^
|
||||
|
||||
On Linux, the Python development package may include a ``python3-config``
|
||||
command that prints out the required compiler flags.
|
||||
If you use it, check that it corresponds to the CPython interpreter you'll use
|
||||
to load the module.
|
||||
Then, start with the following command:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
gcc --shared $(python3-config --cflags --ldflags) spammodule.c -o spam.so
|
||||
|
||||
This should generate a ``spam.so`` file that you need to put in a directory
|
||||
on :py:attr:`sys.path`.
|
||||
|
||||
|
||||
.. rubric:: Footnotes
|
||||
|
||||
.. [#why-spam] ``spam`` is the favorite food of Monty Python fans...
|
||||
.. [#why-spammodule] The source file name is entirely up to you,
|
||||
though some tools can be picky about the ``.c`` extension.
|
||||
This tutorial uses the traditional ``*module.c`` suffix.
|
||||
Some people would just use :file:`spam.c` to implement a module
|
||||
named ``spam``,
|
||||
projects where Python isn't the primary language might use ``py_spam.c``,
|
||||
and so on.
|
||||
.. [#stdlib-h] Including :file:`stdlib.h` is technically not necessary,
|
||||
since :file:`Python.h` includes it and
|
||||
:ref:`several other standard headers <capi-system-includes>` for its own use
|
||||
or for backwards compatibility.
|
||||
However, it is good practice to explicitly include what you need.
|
||||
.. [#why-pymethoddef] The :c:type:`!PyMethodDef` structure is also used
|
||||
to create methods of classes, so there's no separate
|
||||
":c:type:`!PyFunctionDef`".
|
||||
.. [#why-pylongfromlong] The name :c:func:`PyLong_FromLong`
|
||||
might not seem obvious.
|
||||
``PyLong`` refers to a the Python :py:class:`int`, which was originally
|
||||
called ``long``; the ``FromLong`` refers to the C ``long`` (or ``long int``)
|
||||
type.
|
||||
.. [#why-pyunicodeasutf8] Here, ``PyUnicode`` refers to the original name of
|
||||
the Python :py:class:`str` class: ``unicode``.
|
||||
|
|
@ -5,17 +5,15 @@
|
|||
##################################################
|
||||
|
||||
This document describes how to write modules in C or C++ to extend the Python
|
||||
interpreter with new modules. Those modules can do what Python code does --
|
||||
define functions, object types and methods -- but also interact with native
|
||||
libraries or achieve better performance by avoiding the overhead of an
|
||||
interpreter. The document also describes how
|
||||
interpreter with new modules. Those modules can not only define new functions
|
||||
but also new object types and their methods. The document also describes how
|
||||
to embed the Python interpreter in another application, for use as an extension
|
||||
language. Finally, it shows how to compile and link extension modules so that
|
||||
they can be loaded dynamically (at run time) into the interpreter, if the
|
||||
underlying operating system supports this feature.
|
||||
|
||||
This document assumes basic knowledge about C and Python. For an informal
|
||||
introduction to Python, see :ref:`tutorial-index`. :ref:`reference-index`
|
||||
This document assumes basic knowledge about Python. For an informal
|
||||
introduction to the language, see :ref:`tutorial-index`. :ref:`reference-index`
|
||||
gives a more formal definition of the language. :ref:`library-index` documents
|
||||
the existing object types, functions and modules (both built-in and written in
|
||||
Python) that give the language its wide application range.
|
||||
|
|
@ -23,75 +21,37 @@ Python) that give the language its wide application range.
|
|||
For a detailed description of the whole Python/C API, see the separate
|
||||
:ref:`c-api-index`.
|
||||
|
||||
To support extensions, Python's C API (Application Programmers Interface)
|
||||
defines a set of functions, macros and variables that provide access to most
|
||||
aspects of the Python run-time system. The Python API is incorporated in a C
|
||||
source file by including the header ``"Python.h"``.
|
||||
|
||||
.. note::
|
||||
|
||||
The C extension interface is specific to CPython, and extension modules do
|
||||
not work on other Python implementations. In many cases, it is possible to
|
||||
avoid writing C extensions and preserve portability to other implementations.
|
||||
For example, if your use case is calling C library functions or system calls,
|
||||
you should consider using the :mod:`ctypes` module or the `cffi
|
||||
<https://cffi.readthedocs.io/>`_ library rather than writing
|
||||
custom C code.
|
||||
These modules let you write Python code to interface with C code and are more
|
||||
portable between implementations of Python than writing and compiling a C
|
||||
extension module.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
first-extension-module.rst
|
||||
extending.rst
|
||||
newtypes_tutorial.rst
|
||||
newtypes.rst
|
||||
building.rst
|
||||
windows.rst
|
||||
embedding.rst
|
||||
|
||||
|
||||
Recommended third party tools
|
||||
=============================
|
||||
|
||||
This document only covers the basic tools for creating extensions provided
|
||||
This guide only covers the basic tools for creating extensions provided
|
||||
as part of this version of CPython. Some :ref:`third party tools
|
||||
<c-api-tools>` offer both simpler and more sophisticated approaches to creating
|
||||
C and C++ extensions for Python.
|
||||
|
||||
While this document is aimed at extension authors, it should also be helpful to
|
||||
the authors of such tools.
|
||||
For example, the tutorial module can serve as a simple test case for a build
|
||||
tool or sample expected output of a code generator.
|
||||
|
||||
|
||||
C API Tutorial
|
||||
==============
|
||||
|
||||
This tutorial describes how to write a simple module in C or C++,
|
||||
using the Python C API -- that is, using the basic tools provided
|
||||
as part of this version of CPython.
|
||||
|
||||
|
||||
#. :ref:`first-extension-module`
|
||||
|
||||
|
||||
Guides for intermediate topics
|
||||
==============================
|
||||
Creating extensions without third party tools
|
||||
=============================================
|
||||
|
||||
This section of the guide covers creating C and C++ extensions without
|
||||
assistance from third party tools. It is intended primarily for creators
|
||||
of those tools, rather than being a recommended way to create your own
|
||||
C extensions.
|
||||
|
||||
* :ref:`extending-intro`
|
||||
* :ref:`defining-new-types`
|
||||
* :ref:`new-types-topics`
|
||||
* :ref:`building`
|
||||
* :ref:`building-on-windows`
|
||||
.. seealso::
|
||||
|
||||
:pep:`489` -- Multi-phase extension module initialization
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:numbered:
|
||||
|
||||
extending.rst
|
||||
newtypes_tutorial.rst
|
||||
newtypes.rst
|
||||
building.rst
|
||||
windows.rst
|
||||
|
||||
Embedding the CPython runtime in a larger application
|
||||
=====================================================
|
||||
|
|
@ -101,4 +61,8 @@ interpreter as the main application, it is desirable to instead embed
|
|||
the CPython runtime inside a larger application. This section covers
|
||||
some of the details involved in doing that successfully.
|
||||
|
||||
* :ref:`embedding`
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:numbered:
|
||||
|
||||
embedding.rst
|
||||
|
|
|
|||
|
|
@ -560,8 +560,6 @@ For an object to be weakly referenceable, the extension type must set the
|
|||
field. The legacy :c:member:`~PyTypeObject.tp_weaklistoffset` field should
|
||||
be left as zero.
|
||||
|
||||
If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set.
|
||||
|
||||
Concretely, here is how the statically declared type object would look::
|
||||
|
||||
static PyTypeObject TrivialType = {
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ How do I get documentation on Python?
|
|||
-------------------------------------
|
||||
|
||||
The standard documentation for the current stable version of Python is available
|
||||
at https://docs.python.org/3/. EPUB, plain text, and downloadable HTML versions are
|
||||
at https://docs.python.org/3/. PDF, plain text, and downloadable HTML versions are
|
||||
also available at https://docs.python.org/3/download.html.
|
||||
|
||||
The documentation is written in reStructuredText and processed by `the Sphinx
|
||||
|
|
|
|||
183
Doc/glossary.rst
183
Doc/glossary.rst
|
|
@ -134,14 +134,6 @@ Glossary
|
|||
iterator's :meth:`~object.__anext__` method until it raises a
|
||||
:exc:`StopAsyncIteration` exception. Introduced by :pep:`492`.
|
||||
|
||||
atomic operation
|
||||
An operation that appears to execute as a single, indivisible step: no
|
||||
other thread can observe it half-done, and its effects become visible all
|
||||
at once. Python does not guarantee that high-level statements are atomic
|
||||
(for example, ``x += 1`` performs multiple bytecode operations and is not
|
||||
atomic). Atomicity is only guaranteed where explicitly documented. See
|
||||
also :term:`race condition` and :term:`data race`.
|
||||
|
||||
attached thread state
|
||||
|
||||
A :term:`thread state` that is active for the current OS thread.
|
||||
|
|
@ -297,22 +289,6 @@ Glossary
|
|||
advanced mathematical feature. If you're not aware of a need for them,
|
||||
it's almost certain you can safely ignore them.
|
||||
|
||||
concurrency
|
||||
The ability of a computer program to perform multiple tasks at the same
|
||||
time. Python provides libraries for writing programs that make use of
|
||||
different forms of concurrency. :mod:`asyncio` is a library for dealing
|
||||
with asynchronous tasks and coroutines. :mod:`threading` provides
|
||||
access to operating system threads and :mod:`multiprocessing` to
|
||||
operating system processes. Multi-core processors can execute threads and
|
||||
processes on different CPU cores at the same time (see
|
||||
:term:`parallelism`).
|
||||
|
||||
concurrent modification
|
||||
When multiple threads modify shared data at the same time. Concurrent
|
||||
modification without proper synchronization can cause
|
||||
:term:`race conditions <race condition>`, and might also trigger a
|
||||
:term:`data race <data race>`, data corruption, or both.
|
||||
|
||||
context
|
||||
This term has different meanings depending on where and how it is used.
|
||||
Some common meanings:
|
||||
|
|
@ -387,28 +363,6 @@ Glossary
|
|||
the :term:`cyclic garbage collector <garbage collection>` is to identify these groups and break the reference
|
||||
cycles so that the memory can be reclaimed.
|
||||
|
||||
data race
|
||||
A situation where multiple threads access the same memory location
|
||||
concurrently, at least one of the accesses is a write, and the threads
|
||||
do not use any synchronization to control their access. Data races
|
||||
lead to :term:`non-deterministic` behavior and can cause data corruption.
|
||||
Proper use of :term:`locks <lock>` and other :term:`synchronization primitives
|
||||
<synchronization primitive>` prevents data races. Note that data races
|
||||
can only happen in native code, but that :term:`native code` might be
|
||||
exposed in a Python API. See also :term:`race condition` and
|
||||
:term:`thread-safe`.
|
||||
|
||||
deadlock
|
||||
A situation in which two or more tasks (threads, processes, or coroutines)
|
||||
wait indefinitely for each other to release resources or complete actions,
|
||||
preventing any from making progress. For example, if thread A holds lock
|
||||
1 and waits for lock 2, while thread B holds lock 2 and waits for lock 1,
|
||||
both threads will wait indefinitely. In Python this often arises from
|
||||
acquiring multiple locks in conflicting orders or from circular
|
||||
join/await dependencies. Deadlocks can be avoided by always acquiring
|
||||
multiple :term:`locks <lock>` in a consistent order. See also
|
||||
:term:`lock` and :term:`reentrant`.
|
||||
|
||||
decorator
|
||||
A function returning another function, usually applied as a function
|
||||
transformation using the ``@wrapper`` syntax. Common examples for
|
||||
|
|
@ -708,14 +662,6 @@ Glossary
|
|||
requires the GIL to be held in order to use it. This refers to having an
|
||||
:term:`attached thread state`.
|
||||
|
||||
global state
|
||||
Data that is accessible throughout a program, such as module-level
|
||||
variables, class variables, or C static variables in :term:`extension modules
|
||||
<extension module>`. In multi-threaded programs, global state shared
|
||||
between threads typically requires synchronization to avoid
|
||||
:term:`race conditions <race condition>` and
|
||||
:term:`data races <data race>`.
|
||||
|
||||
hash-based pyc
|
||||
A bytecode cache file that uses the hash rather than the last-modified
|
||||
time of the corresponding source file to determine its validity. See
|
||||
|
|
@ -760,9 +706,7 @@ Glossary
|
|||
tuples. Such an object cannot be altered. A new object has to
|
||||
be created if a different value has to be stored. They play an important
|
||||
role in places where a constant hash value is needed, for example as a key
|
||||
in a dictionary. Immutable objects are inherently :term:`thread-safe`
|
||||
because their state cannot be modified after creation, eliminating concerns
|
||||
about improperly synchronized :term:`concurrent modification`.
|
||||
in a dictionary.
|
||||
|
||||
import path
|
||||
A list of locations (or :term:`path entries <path entry>`) that are
|
||||
|
|
@ -852,9 +796,8 @@ Glossary
|
|||
|
||||
CPython does not consistently apply the requirement that an iterator
|
||||
define :meth:`~iterator.__iter__`.
|
||||
And also please note that :term:`free-threaded <free threading>`
|
||||
CPython does not guarantee :term:`thread-safe` behavior of iterator
|
||||
operations.
|
||||
And also please note that the free-threading CPython does not guarantee
|
||||
the thread-safety of iterator operations.
|
||||
|
||||
|
||||
key function
|
||||
|
|
@ -870,7 +813,7 @@ Glossary
|
|||
:func:`itertools.groupby`.
|
||||
|
||||
There are several ways to create a key function. For example. the
|
||||
:meth:`str.casefold` method can serve as a key function for case insensitive
|
||||
:meth:`str.lower` method can serve as a key function for case insensitive
|
||||
sorts. Alternatively, a key function can be built from a
|
||||
:keyword:`lambda` expression such as ``lambda r: (r[0], r[2])``. Also,
|
||||
:func:`operator.attrgetter`, :func:`operator.itemgetter`, and
|
||||
|
|
@ -892,11 +835,10 @@ Glossary
|
|||
:keyword:`if` statements.
|
||||
|
||||
In a multi-threaded environment, the LBYL approach can risk introducing a
|
||||
:term:`race condition` between "the looking" and "the leaping". For example,
|
||||
the code, ``if key in mapping: return mapping[key]`` can fail if another
|
||||
race condition between "the looking" and "the leaping". For example, the
|
||||
code, ``if key in mapping: return mapping[key]`` can fail if another
|
||||
thread removes *key* from *mapping* after the test, but before the lookup.
|
||||
This issue can be solved with :term:`locks <lock>` or by using the
|
||||
:term:`EAFP` approach. See also :term:`thread-safe`.
|
||||
This issue can be solved with locks or by using the EAFP approach.
|
||||
|
||||
lexical analyzer
|
||||
|
||||
|
|
@ -915,19 +857,6 @@ Glossary
|
|||
clause is optional. If omitted, all elements in ``range(256)`` are
|
||||
processed.
|
||||
|
||||
lock
|
||||
A :term:`synchronization primitive` that allows only one thread at a
|
||||
time to access a shared resource. A thread must acquire a lock before
|
||||
accessing the protected resource and release it afterward. If a thread
|
||||
attempts to acquire a lock that is already held by another thread, it
|
||||
will block until the lock becomes available. Python's :mod:`threading`
|
||||
module provides :class:`~threading.Lock` (a basic lock) and
|
||||
:class:`~threading.RLock` (a :term:`reentrant` lock). Locks are used
|
||||
to prevent :term:`race conditions <race condition>` and ensure
|
||||
:term:`thread-safe` access to shared data. Alternative design patterns
|
||||
to locks exist such as queues, producer/consumer patterns, and
|
||||
thread-local state. See also :term:`deadlock`, and :term:`reentrant`.
|
||||
|
||||
loader
|
||||
An object that loads a module.
|
||||
It must define the :meth:`!exec_module` and :meth:`!create_module` methods
|
||||
|
|
@ -1013,11 +942,8 @@ Glossary
|
|||
See :term:`method resolution order`.
|
||||
|
||||
mutable
|
||||
An :term:`object` with state that is allowed to change during the course
|
||||
of the program. In multi-threaded programs, mutable objects that are
|
||||
shared between threads require careful synchronization to avoid
|
||||
:term:`race conditions <race condition>`. See also :term:`immutable`,
|
||||
:term:`thread-safe`, and :term:`concurrent modification`.
|
||||
Mutable objects can change their value but keep their :func:`id`. See
|
||||
also :term:`immutable`.
|
||||
|
||||
named tuple
|
||||
The term "named tuple" applies to any type or class that inherits from
|
||||
|
|
@ -1069,13 +995,6 @@ Glossary
|
|||
|
||||
See also :term:`module`.
|
||||
|
||||
native code
|
||||
Code that is compiled to machine instructions and runs directly on the
|
||||
processor, as opposed to code that is interpreted or runs in a virtual
|
||||
machine. In the context of Python, native code typically refers to
|
||||
C, C++, Rust or Fortran code in :term:`extension modules <extension module>`
|
||||
that can be called from Python. See also :term:`extension module`.
|
||||
|
||||
nested scope
|
||||
The ability to refer to a variable in an enclosing definition. For
|
||||
instance, a function defined inside another function can refer to
|
||||
|
|
@ -1092,15 +1011,6 @@ Glossary
|
|||
properties, :meth:`~object.__getattribute__`, class methods, and static
|
||||
methods.
|
||||
|
||||
non-deterministic
|
||||
Behavior where the outcome of a program can vary between executions with
|
||||
the same inputs. In multi-threaded programs, non-deterministic behavior
|
||||
often results from :term:`race conditions <race condition>` where the
|
||||
relative timing or interleaving of threads affects the result.
|
||||
Proper synchronization using :term:`locks <lock>` and other
|
||||
:term:`synchronization primitives <synchronization primitive>` helps
|
||||
ensure deterministic behavior.
|
||||
|
||||
object
|
||||
Any data with state (attributes or value) and defined behavior
|
||||
(methods). Also the ultimate base class of any :term:`new-style
|
||||
|
|
@ -1115,15 +1025,6 @@ Glossary
|
|||
applied to all scopes, only those relying on a known set of local
|
||||
and nonlocal variable names are restricted to optimized scopes.
|
||||
|
||||
optional module
|
||||
An :term:`extension module` that is part of the :term:`standard library`,
|
||||
but may be absent in some builds of :term:`CPython`,
|
||||
usually due to missing third-party libraries or because the module
|
||||
is not available for a given platform.
|
||||
|
||||
See :ref:`optional-module-requirements` for a list of optional modules
|
||||
that require third-party libraries.
|
||||
|
||||
package
|
||||
A Python :term:`module` which can contain submodules or recursively,
|
||||
subpackages. Technically, a package is a Python module with a
|
||||
|
|
@ -1131,16 +1032,6 @@ Glossary
|
|||
|
||||
See also :term:`regular package` and :term:`namespace package`.
|
||||
|
||||
parallelism
|
||||
Executing multiple operations at the same time (e.g. on multiple CPU
|
||||
cores). In Python builds with the
|
||||
:term:`global interpreter lock (GIL) <global interpreter lock>`, only one
|
||||
thread runs Python bytecode at a time, so taking advantage of multiple
|
||||
CPU cores typically involves multiple processes
|
||||
(e.g. :mod:`multiprocessing`) or native extensions that release the GIL.
|
||||
In :term:`free-threaded <free threading>` Python, multiple Python threads
|
||||
can run Python code simultaneously on different cores.
|
||||
|
||||
parameter
|
||||
A named entity in a :term:`function` (or method) definition that
|
||||
specifies an :term:`argument` (or in some cases, arguments) that the
|
||||
|
|
@ -1315,18 +1206,6 @@ Glossary
|
|||
>>> email.mime.text.__name__
|
||||
'email.mime.text'
|
||||
|
||||
race condition
|
||||
A condition of a program where the its 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
|
||||
reproduce. A :term:`data race` is a specific type of race condition
|
||||
involving unsynchronized access to shared memory. The :term:`LBYL`
|
||||
coding style is particularly susceptible to race conditions in
|
||||
multi-threaded code. Using :term:`locks <lock>` and other
|
||||
:term:`synchronization primitives <synchronization primitive>`
|
||||
helps prevent race conditions.
|
||||
|
||||
reference count
|
||||
The number of references to an object. When the reference count of an
|
||||
object drops to zero, it is deallocated. Some objects are
|
||||
|
|
@ -1348,25 +1227,6 @@ Glossary
|
|||
|
||||
See also :term:`namespace package`.
|
||||
|
||||
reentrant
|
||||
A property of a function or :term:`lock` that allows it to be called or
|
||||
acquired multiple times by the same thread without causing errors or a
|
||||
:term:`deadlock`.
|
||||
|
||||
For functions, reentrancy means the function can be safely called again
|
||||
before a previous invocation has completed, which is important when
|
||||
functions may be called recursively or from signal handlers. Thread-unsafe
|
||||
functions may be :term:`non-deterministic` if they're called reentrantly in a
|
||||
multithreaded program.
|
||||
|
||||
For locks, Python's :class:`threading.RLock` (reentrant lock) is
|
||||
reentrant, meaning a thread that already holds the lock can acquire it
|
||||
again without blocking. In contrast, :class:`threading.Lock` is not
|
||||
reentrant - attempting to acquire it twice from the same thread will cause
|
||||
a deadlock.
|
||||
|
||||
See also :term:`lock` and :term:`deadlock`.
|
||||
|
||||
REPL
|
||||
An acronym for the "read–eval–print loop", another name for the
|
||||
:term:`interactive` interpreter shell.
|
||||
|
|
@ -1471,18 +1331,6 @@ Glossary
|
|||
|
||||
See also :term:`borrowed reference`.
|
||||
|
||||
synchronization primitive
|
||||
A basic building block for coordinating (synchronizing) the execution of
|
||||
multiple threads to ensure :term:`thread-safe` access to shared resources.
|
||||
Python's :mod:`threading` module provides several synchronization primitives
|
||||
including :class:`~threading.Lock`, :class:`~threading.RLock`,
|
||||
:class:`~threading.Semaphore`, :class:`~threading.Condition`,
|
||||
:class:`~threading.Event`, and :class:`~threading.Barrier`. Additionally,
|
||||
the :mod:`queue` module provides multi-producer, multi-consumer queues
|
||||
that are especially useful in multithreaded programs. These
|
||||
primitives help prevent :term:`race conditions <race condition>` and
|
||||
coordinate thread execution. See also :term:`lock`.
|
||||
|
||||
t-string
|
||||
t-strings
|
||||
String literals prefixed with ``t`` or ``T`` are commonly called
|
||||
|
|
@ -1535,19 +1383,6 @@ Glossary
|
|||
See :ref:`Thread State and the Global Interpreter Lock <threads>` for more
|
||||
information.
|
||||
|
||||
thread-safe
|
||||
A module, function, or class that behaves correctly when used by multiple
|
||||
threads concurrently. Thread-safe code uses appropriate
|
||||
:term:`synchronization primitives <synchronization primitive>` like
|
||||
:term:`locks <lock>` to protect shared mutable state, or is designed
|
||||
to avoid shared mutable state entirely. In the
|
||||
:term:`free-threaded <free threading>` build, built-in types like
|
||||
:class:`dict`, :class:`list`, and :class:`set` use internal locking
|
||||
to make many operations thread-safe, although thread safety is not
|
||||
necessarily guaranteed. Code that is not thread-safe may experience
|
||||
:term:`race conditions <race condition>` and :term:`data races <data race>`
|
||||
when used in multi-threaded programs.
|
||||
|
||||
token
|
||||
|
||||
A small unit of source code, generated by the
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.. _a-conceptual-overview-of-asyncio:
|
||||
|
||||
****************************************
|
||||
A conceptual overview of :mod:`!asyncio`
|
||||
A Conceptual Overview of :mod:`!asyncio`
|
||||
****************************************
|
||||
|
||||
This :ref:`HOWTO <how-tos>` article seeks to help you build a sturdy mental
|
||||
|
|
@ -37,15 +37,15 @@ In part 1, we'll cover the main, high-level building blocks of :mod:`!asyncio`:
|
|||
the event loop, coroutine functions, coroutine objects, tasks, and ``await``.
|
||||
|
||||
==========
|
||||
Event loop
|
||||
Event Loop
|
||||
==========
|
||||
|
||||
Everything in :mod:`!asyncio` happens relative to the event loop.
|
||||
It's the star of the show, but prefers to work behind the scenes, managing
|
||||
and coordinating resources.
|
||||
It's the star of the show.
|
||||
It's like an orchestra conductor.
|
||||
It's behind the scenes managing resources.
|
||||
Some power is explicitly granted to it, but a lot of its ability to get things
|
||||
done comes from the respect and cooperation of its band members.
|
||||
done comes from the respect and cooperation of its worker bees.
|
||||
|
||||
In more technical terms, the event loop contains a collection of jobs to be run.
|
||||
Some jobs are added directly by you, and some indirectly by :mod:`!asyncio`.
|
||||
|
|
@ -59,7 +59,7 @@ This process repeats indefinitely, with the event loop cycling endlessly
|
|||
onwards.
|
||||
If there are no more jobs pending execution, the event loop is smart enough to
|
||||
rest and avoid needlessly wasting CPU cycles, and will come back when there's
|
||||
more work to be done, such as when I/O operations complete or timers expire.
|
||||
more work to be done.
|
||||
|
||||
Effective execution relies on jobs sharing well and cooperating; a greedy job
|
||||
could hog control and leave the other jobs to starve, rendering the overall
|
||||
|
|
@ -170,17 +170,14 @@ Roughly speaking, :ref:`tasks <asyncio-task-obj>` are coroutines (not coroutine
|
|||
functions) tied to an event loop.
|
||||
A task also maintains a list of callback functions whose importance will become
|
||||
clear in a moment when we discuss :keyword:`await`.
|
||||
The recommended way to create tasks is via :func:`asyncio.create_task`.
|
||||
|
||||
Creating a task automatically schedules it for execution (by adding a
|
||||
callback to run it in the event loop's to-do list, that is, collection of jobs).
|
||||
The recommended way to create tasks is via :func:`asyncio.create_task`.
|
||||
|
||||
:mod:`!asyncio` automatically associates tasks with the event loop for you.
|
||||
This automatic association was purposely designed into :mod:`!asyncio` for
|
||||
the sake of simplicity.
|
||||
Without it, you'd have to keep track of the event loop object and pass it to
|
||||
any coroutine function that wants to create tasks, adding redundant clutter
|
||||
to your code.
|
||||
Since there's only one event loop (in each thread), :mod:`!asyncio` takes care of
|
||||
associating the task with the event loop for you. As such, there's no need
|
||||
to specify the event loop.
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -253,10 +250,6 @@ different ways::
|
|||
In a crucial way, the behavior of ``await`` depends on the type of object
|
||||
being awaited.
|
||||
|
||||
^^^^^^^^^^^^^^
|
||||
Awaiting tasks
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Awaiting a task will cede control from the current task or coroutine to
|
||||
the event loop.
|
||||
In the process of relinquishing control, a few important things happen.
|
||||
|
|
@ -288,10 +281,6 @@ This is a basic, yet reliable mental model.
|
|||
In practice, the control handoffs are slightly more complex, but not by much.
|
||||
In part 2, we'll walk through the details that make this possible.
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
Awaiting coroutines
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Unlike tasks, awaiting a coroutine does not hand control back to the event
|
||||
loop!**
|
||||
Wrapping a coroutine in a task first, then awaiting that would cede
|
||||
|
|
@ -358,10 +347,8 @@ The design intentionally trades off some conceptual clarity around usage of
|
|||
``await`` for improved performance.
|
||||
Each time a task is awaited, control needs to be passed all the way up the
|
||||
call stack to the event loop.
|
||||
Then, the event loop needs to manage its internal state and work through
|
||||
its processing logic to resume the next job.
|
||||
That might sound minor, but in a large program with many ``await``\ s, that
|
||||
overhead can add up to a non-negligible performance drag.
|
||||
That might sound minor, but in a large program with many ``await`` statements and a deep
|
||||
call stack, that overhead can add up to a meaningful performance drag.
|
||||
|
||||
------------------------------------------------
|
||||
A conceptual overview part 2: the nuts and bolts
|
||||
|
|
@ -377,8 +364,7 @@ and how to make your own asynchronous operators.
|
|||
The inner workings of coroutines
|
||||
================================
|
||||
|
||||
:mod:`!asyncio` leverages four components of Python to pass
|
||||
around control.
|
||||
:mod:`!asyncio` leverages four components to pass around control.
|
||||
|
||||
:meth:`coroutine.send(arg) <generator.send>` is the method used to start or
|
||||
resume a coroutine.
|
||||
|
|
@ -462,9 +448,9 @@ That might sound odd to you. You might be thinking:
|
|||
That causes the error: ``SyntaxError: yield from not allowed in a coroutine.``
|
||||
This was intentionally designed for the sake of simplicity -- mandating only
|
||||
one way of using coroutines.
|
||||
Despite that, ``yield from`` and ``await`` effectively do the same thing.
|
||||
Initially ``yield`` was barred as well, but was re-accepted to allow for
|
||||
async generators.
|
||||
Despite that, ``yield from`` and ``await`` effectively do the same thing.
|
||||
|
||||
=======
|
||||
Futures
|
||||
|
|
|
|||
|
|
@ -45,12 +45,9 @@ single-phase initialization.
|
|||
Multi-Phase Initialization
|
||||
..........................
|
||||
|
||||
Extensions that use :ref:`multi-phase initialization <multi-phase-initialization>`
|
||||
(functions like :c:func:`PyModuleDef_Init`,
|
||||
:c:func:`PyModExport_* <PyModExport_modulename>` export hook,
|
||||
:c:func:`PyModule_FromSlotsAndSpec`) should add a
|
||||
:c:data:`Py_mod_gil` slot in the module definition.
|
||||
If your extension supports older versions of CPython,
|
||||
Extensions that use multi-phase initialization (i.e.,
|
||||
:c:func:`PyModuleDef_Init`) should add a :c:data:`Py_mod_gil` slot in the
|
||||
module definition. If your extension supports older versions of CPython,
|
||||
you should guard the slot with a :c:data:`PY_VERSION_HEX` check.
|
||||
|
||||
::
|
||||
|
|
@ -63,12 +60,18 @@ you should guard the slot with a :c:data:`PY_VERSION_HEX` check.
|
|||
{0, NULL}
|
||||
};
|
||||
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
.m_slots = module_slots,
|
||||
...
|
||||
};
|
||||
|
||||
|
||||
Single-Phase Initialization
|
||||
...........................
|
||||
|
||||
Extensions that use legacy :ref:`single-phase initialization <single-phase-initialization>`
|
||||
(that is, :c:func:`PyModule_Create`) should call :c:func:`PyUnstable_Module_SetGIL` to
|
||||
Extensions that use single-phase initialization (i.e.,
|
||||
:c:func:`PyModule_Create`) should call :c:func:`PyUnstable_Module_SetGIL` to
|
||||
indicate that they support running with the GIL disabled. The function is
|
||||
only defined in the free-threaded build, so you should guard the call with
|
||||
``#ifdef Py_GIL_DISABLED`` to avoid compilation errors in the regular build.
|
||||
|
|
@ -200,7 +203,7 @@ Memory Allocation APIs
|
|||
Python's memory management C API provides functions in three different
|
||||
:ref:`allocation domains <allocator-domains>`: "raw", "mem", and "object".
|
||||
For thread-safety, the free-threaded build requires that only Python objects
|
||||
are allocated using the object domain, and that all Python objects are
|
||||
are allocated using the object domain, and that all Python object are
|
||||
allocated using that domain. This differs from the prior Python versions,
|
||||
where this was only a best practice and not a hard requirement.
|
||||
|
||||
|
|
@ -341,12 +344,12 @@ This means you cannot rely on nested critical sections to lock multiple objects
|
|||
at once, as the inner critical section may suspend the outer ones. Instead, use
|
||||
:c:macro:`Py_BEGIN_CRITICAL_SECTION2` to lock two objects simultaneously.
|
||||
|
||||
Note that the locks described above are only :c:type:`PyMutex` based locks.
|
||||
Note that the locks described above are only :c:type:`!PyMutex` based locks.
|
||||
The critical section implementation does not know about or affect other locking
|
||||
mechanisms that might be in use, like POSIX mutexes. Also note that while
|
||||
blocking on any :c:type:`PyMutex` causes the critical sections to be
|
||||
blocking on any :c:type:`!PyMutex` causes the critical sections to be
|
||||
suspended, only the mutexes that are part of the critical sections are
|
||||
released. If :c:type:`PyMutex` is used without a critical section, it will
|
||||
released. If :c:type:`!PyMutex` is used without a critical section, it will
|
||||
not be released and therefore does not get the same deadlock avoidance.
|
||||
|
||||
Important Considerations
|
||||
|
|
@ -394,8 +397,7 @@ The wheels, shared libraries, and binaries are indicated by a ``t`` suffix.
|
|||
* `pypa/manylinux <https://github.com/pypa/manylinux>`_ supports the
|
||||
free-threaded build, with the ``t`` suffix, such as ``python3.13t``.
|
||||
* `pypa/cibuildwheel <https://github.com/pypa/cibuildwheel>`_ supports the
|
||||
free-threaded build on Python 3.13 and 3.14. On Python 3.14, free-threaded
|
||||
wheels will be built by default. On Python 3.13, you will need to set
|
||||
free-threaded build if you set
|
||||
`CIBW_ENABLE to cpython-freethreading <https://cibuildwheel.pypa.io/en/stable/options/#enable>`_.
|
||||
|
||||
Limited C API and Stable ABI
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ available processing power by running threads in parallel on available CPU cores
|
|||
While not all software will benefit from this automatically, programs
|
||||
designed with threading in mind will run faster on multi-core hardware.
|
||||
|
||||
Some third-party packages, in particular ones
|
||||
The free-threaded mode is working and continues to be improved, but
|
||||
there is some additional overhead in single-threaded workloads compared
|
||||
to the regular build. Additionally, third-party packages, in particular ones
|
||||
with an :term:`extension module`, may not be ready for use in a
|
||||
free-threaded build, and will re-enable the :term:`GIL`.
|
||||
|
||||
|
|
@ -99,42 +101,60 @@ This section describes known limitations of the free-threaded CPython build.
|
|||
Immortalization
|
||||
---------------
|
||||
|
||||
In the free-threaded build, some objects are :term:`immortal`.
|
||||
The free-threaded build of the 3.13 release makes some objects :term:`immortal`.
|
||||
Immortal objects are not deallocated and have reference counts that are
|
||||
never modified. This is done to avoid reference count contention that would
|
||||
prevent efficient multi-threaded scaling.
|
||||
|
||||
As of the 3.14 release, immortalization is limited to:
|
||||
An object will be made immortal when a new thread is started for the first time
|
||||
after the main thread is running. The following objects are immortalized:
|
||||
|
||||
* Code constants: numeric literals, string literals, and tuple literals
|
||||
composed of other constants.
|
||||
* Strings interned by :func:`sys.intern`.
|
||||
* :ref:`function <user-defined-funcs>` objects declared at the module level
|
||||
* :ref:`method <instance-methods>` descriptors
|
||||
* :ref:`code <code-objects>` objects
|
||||
* :term:`module` objects and their dictionaries
|
||||
* :ref:`classes <classes>` (type objects)
|
||||
|
||||
Because immortal objects are never deallocated, applications that create many
|
||||
objects of these types may see increased memory usage. This is expected to be
|
||||
addressed in the 3.14 release.
|
||||
|
||||
Additionally, numeric and string literals in the code as well as strings
|
||||
returned by :func:`sys.intern` are also immortalized. This behavior is
|
||||
expected to remain in the 3.14 free-threaded build.
|
||||
|
||||
|
||||
Frame objects
|
||||
-------------
|
||||
|
||||
It is not safe to access :attr:`frame.f_locals` from a :ref:`frame <frame-objects>`
|
||||
object if that frame is currently executing in another thread, and doing so may
|
||||
crash the interpreter.
|
||||
|
||||
It is not safe to access :ref:`frame <frame-objects>` objects from other
|
||||
threads and doing so may cause your program to crash . This means that
|
||||
:func:`sys._current_frames` is generally not safe to use in a free-threaded
|
||||
build. Functions like :func:`inspect.currentframe` and :func:`sys._getframe`
|
||||
are generally safe as long as the resulting frame object is not passed to
|
||||
another thread.
|
||||
|
||||
Iterators
|
||||
---------
|
||||
|
||||
It is generally not thread-safe to access the same iterator object from
|
||||
multiple threads concurrently, and threads may see duplicate or missing
|
||||
elements.
|
||||
Sharing the same iterator object between multiple threads is generally not
|
||||
safe and threads may see duplicate or missing elements when iterating or crash
|
||||
the interpreter.
|
||||
|
||||
|
||||
Single-threaded performance
|
||||
---------------------------
|
||||
|
||||
The free-threaded build has additional overhead when executing Python code
|
||||
compared to the default GIL-enabled build. The amount of overhead depends
|
||||
on the workload and hardware. On the pyperformance benchmark suite, the
|
||||
average overhead ranges from about 1% on macOS aarch64 to 8% on x86-64 Linux
|
||||
systems.
|
||||
compared to the default GIL-enabled build. In 3.13, this overhead is about
|
||||
40% on the `pyperformance <https://pyperformance.readthedocs.io/>`_ suite.
|
||||
Programs that spend most of their time in C extensions or I/O will see
|
||||
less of an impact. The largest impact is because the specializing adaptive
|
||||
interpreter (:pep:`659`) is disabled in the free-threaded build. We expect
|
||||
to re-enable it in a thread-safe way in the 3.14 release. This overhead is
|
||||
expected to be reduced in upcoming Python release. We are aiming for an
|
||||
overhead of 10% or less on the pyperformance suite compared to the default
|
||||
GIL-enabled build.
|
||||
|
||||
|
||||
Behavioral changes
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
Functional Programming HOWTO
|
||||
********************************
|
||||
|
||||
:Author: \A. M. Kuchling
|
||||
:Author: A. M. Kuchling
|
||||
:Release: 0.32
|
||||
|
||||
In this document, we'll take a tour of Python's features suitable for
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ enabled::
|
|||
at Objects/unicodeobject.c:551
|
||||
#7 0x0000000000440d94 in PyUnicodeUCS2_FromString (u=0x5c2b8d "__lltrace__") at Objects/unicodeobject.c:569
|
||||
#8 0x0000000000584abd in PyDict_GetItemString (v=
|
||||
{'Yuck': <type at remote 0xad4730>, '__builtins__': <module at remote 0x7ffff7fd5ee8>, '__file__': 'Lib/test/crashers/nasty_eq_vs_dict.py', '__package__': None, 'y': <Yuck(i=0) at remote 0xaacd80>, 'dict': {0: 0, 1: 1, 2: 2, 3: 3}, '__name__': '__main__', 'z': <Yuck(i=0) at remote 0xaace60>, '__doc__': None}, key=
|
||||
{'Yuck': <type at remote 0xad4730>, '__builtins__': <module at remote 0x7ffff7fd5ee8>, '__file__': 'Lib/test/crashers/nasty_eq_vs_dict.py', '__package__': None, 'y': <Yuck(i=0) at remote 0xaacd80>, 'dict': {0: 0, 1: 1, 2: 2, 3: 3}, '__cached__': None, '__name__': '__main__', 'z': <Yuck(i=0) at remote 0xaace60>, '__doc__': None}, key=
|
||||
0x5c2b8d "__lltrace__") at Objects/dictobject.c:2171
|
||||
|
||||
Notice how the dictionary argument to ``PyDict_GetItemString`` is displayed
|
||||
|
|
|
|||
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