diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml
index b5b2765e43844f9..9b3415fd2b5861d 100644
--- a/.azure-pipelines/ci.yml
+++ b/.azure-pipelines/ci.yml
@@ -1,11 +1,11 @@
-trigger: ['main', '3.12', '3.11', '3.10', '3.9', '3.8', '3.7']
+trigger: ['main', '3.*']
jobs:
- job: Prebuild
displayName: Pre-build checks
pool:
- vmImage: ubuntu-22.04
+ vmImage: ubuntu-24.04
steps:
- template: ./prebuild-checks.yml
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 6f8fe005621c88e..ada5fb0fe64dc29 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -2,11 +2,11 @@ FROM docker.io/library/fedora:40
ENV CC=clang
-ENV WASI_SDK_VERSION=21
+ENV WASI_SDK_VERSION=24
ENV WASI_SDK_PATH=/opt/wasi-sdk
ENV WASMTIME_HOME=/opt/wasmtime
-ENV WASMTIME_VERSION=18.0.3
+ENV WASMTIME_VERSION=22.0.0
ENV WASMTIME_CPU_ARCH=x86_64
RUN dnf -y --nodocs --setopt=install_weak_deps=False install /usr/bin/{blurb,clang,curl,git,ln,tar,xz} 'dnf-command(builddep)' && \
@@ -14,7 +14,7 @@ RUN dnf -y --nodocs --setopt=install_weak_deps=False install /usr/bin/{blurb,cla
dnf -y clean all
RUN mkdir ${WASI_SDK_PATH} && \
- curl --location https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_VERSION}.0-linux.tar.gz | \
+ curl --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
RUN mkdir --parents ${WASMTIME_HOME} && \
diff --git a/.editorconfig b/.editorconfig
index a6187d64f3ce46e..d2801b8c8b60f8b 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,11 +1,11 @@
root = true
-[*.{py,c,cpp,h,js,rst,md,yml}]
+[*.{py,c,cpp,h,js,rst,md,yml,yaml,toml,gram}]
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
-[*.{py,c,cpp,h}]
+[*.{py,c,cpp,h,toml,gram}]
indent_size = 4
[*.rst]
diff --git a/.gitattributes b/.gitattributes
index 5b81d2cb3c90e9c..a1d26bdf42d3132 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -27,14 +27,15 @@ Lib/test/cjkencodings/* noeol
Lib/test/tokenizedata/coding20731.py noeol
Lib/test/decimaltestdata/*.decTest noeol
Lib/test/test_email/data/*.txt noeol
-Lib/test/test_importlib/resources/data01/* noeol
-Lib/test/test_importlib/resources/namespacedata01/* noeol
Lib/test/xmltestdata/* noeol
# Shell scripts should have LF even on Windows because of Cygwin
Lib/venv/scripts/common/activate text eol=lf
Lib/venv/scripts/posix/* text eol=lf
+# Prevent GitHub's web conflict editor from converting LF to CRLF
+*.rst text eol=lf
+
# CRLF files
[attr]dos text eol=crlf
@@ -76,13 +77,16 @@ Include/internal/pycore_ast_state.h generated
Include/internal/pycore_opcode.h generated
Include/internal/pycore_opcode_metadata.h generated
Include/internal/pycore_*_generated.h generated
+Include/internal/pycore_token.h generated
Include/internal/pycore_uop_ids.h generated
Include/internal/pycore_uop_metadata.h generated
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
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 1f5f7e57dc4859f..2827a9942096a82 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -5,10 +5,13 @@
# https://git-scm.com/docs/gitignore#_pattern_format
# GitHub
-.github/** @ezio-melotti @hugovk
+.github/** @ezio-melotti @hugovk @webknjaz
+.github/workflows/jit.yml @savannahostrowski
+Tools/build/compute-changes.py @AA-Turner @hugovk @webknjaz
+Lib/test/test_tools/test_compute_changes.py @AA-Turner @hugovk @webknjaz
# pre-commit
-.pre-commit-config.yaml @hugovk @AlexWaygood
+.pre-commit-config.yaml @hugovk
.ruff.toml @hugovk @AlexWaygood
# Build system
@@ -21,7 +24,8 @@ configure* @erlend-aasland @corona10
**/*context* @1st1
**/*genobject* @markshannon
**/*hamt* @1st1
-**/*jit* @brandtbucher
+**/*jit* @brandtbucher @savannahostrowski
+Python/perf_jit_trampoline.c # Exclude the owners of "**/*jit*", above.
Objects/set* @rhettinger
Objects/dict* @methane @markshannon
Objects/typevarobject.c @JelleZijlstra
@@ -29,20 +33,21 @@ Objects/type* @markshannon
Objects/codeobject.c @markshannon
Objects/frameobject.c @markshannon
Objects/call.c @markshannon
-Python/ceval*.c @markshannon @gvanrossum
-Python/ceval*.h @markshannon @gvanrossum
+Python/ceval*.c @markshannon
+Python/ceval*.h @markshannon
Python/compile.c @markshannon @iritkatriel
Python/assemble.c @markshannon @iritkatriel
Python/flowgraph.c @markshannon @iritkatriel
Python/ast_opt.c @isidentical
-Python/bytecodes.c @markshannon @gvanrossum
-Python/optimizer*.c @markshannon @gvanrossum
+Python/bytecodes.c @markshannon
+Python/optimizer*.c @markshannon
Python/optimizer_analysis.c @Fidget-Spinner
Python/optimizer_bytecodes.c @Fidget-Spinner
Lib/test/test_patma.py @brandtbucher
Lib/test/test_type_*.py @JelleZijlstra
-Lib/test/test_capi/test_misc.py @markshannon @gvanrossum
+Lib/test/test_capi/test_misc.py @markshannon
Tools/c-analyzer/ @ericsnowcurrently
+Tools/check-c-api-docs/ @ZeroIntensity
# dbm
**/*dbm* @corona10 @erlend-aasland @serhiy-storchaka
@@ -150,7 +155,7 @@ Include/internal/pycore_time.h @pganssle @abalkin
/Lib/test/test_tokenize.py @pablogsal @lysnikolaou
# Code generator
-/Tools/cases_generator/ @gvanrossum
+/Tools/cases_generator/ @markshannon
# AST
Python/ast.c @isidentical
@@ -166,7 +171,7 @@ Lib/ast.py @isidentical
**/*multiprocessing* @gpshead
# SQLite 3
-**/*sqlite* @berkerpeksag @erlend-aasland
+**/*sqlite* @erlend-aasland
# subprocess
/Lib/subprocess.py @gpshead
@@ -194,7 +199,6 @@ Doc/c-api/stable.rst @encukou
**/*itertools* @rhettinger
**/*collections* @rhettinger
**/*random* @rhettinger
-**/*queue* @rhettinger
**/*bisect* @rhettinger
**/*heapq* @rhettinger
**/*functools* @rhettinger
@@ -205,6 +209,7 @@ Doc/c-api/stable.rst @encukou
**/*ensurepip* @pfmoore @pradyunsg
**/*idlelib* @terryjreedy
+/Doc/library/idle.rst @terryjreedy
**/*typing* @JelleZijlstra @AlexWaygood
@@ -240,12 +245,12 @@ Doc/howto/clinic.rst @erlend-aasland
**/*interpreteridobject.* @ericsnowcurrently
**/*crossinterp* @ericsnowcurrently
Lib/test/support/interpreters/ @ericsnowcurrently
-Modules/_xx*interp*module.c @ericsnowcurrently
+Modules/_interp*module.c @ericsnowcurrently
Lib/test/test_interpreters/ @ericsnowcurrently
# Android
-**/*Android* @mhsmith
-**/*android* @mhsmith
+**/*Android* @mhsmith @freakboy3742
+**/*android* @mhsmith @freakboy3742
# iOS (but not termios)
**/iOS* @freakboy3742
@@ -266,3 +271,7 @@ Lib/test/test_interpreters/ @ericsnowcurrently
# Config Parser
Lib/configparser.py @jaraco
Lib/test/test_configparser.py @jaraco
+
+# Colorize
+Lib/_colorize.py @hugovk
+Lib/test/test__colorize.py @hugovk
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 4cc2f461dbe2f21..03ea959ca14e282 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -7,10 +7,10 @@ Please read this comment in its entirety. It's quite important.
It should be in the following format:
```
-gh-NNNNN: Summary of the changes made
+gh-NNNNNN: Summary of the changes made
```
-Where: gh-NNNNN refers to the GitHub issue number.
+Where: gh-NNNNNN refers to the GitHub issue number.
Most PRs will require an issue number. Trivial changes, like fixing a typo, do not need an issue.
@@ -20,11 +20,11 @@ If this is a backport PR (PR made against branches other than `main`),
please ensure that the PR title is in the following format:
```
-[X.Y]
(GH-NNNN)
+[X.Y] (GH-NNNNNN)
```
-Where: [X.Y] is the branch name, e.g. [3.6].
+Where: [X.Y] is the branch name, for example: [3.13].
-GH-NNNN refers to the PR number from `main`.
+GH-NNNNNN refers to the PR number from `main`.
-->
diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml
new file mode 100644
index 000000000000000..eacfff24889021b
--- /dev/null
+++ b/.github/actionlint.yaml
@@ -0,0 +1,7 @@
+config-variables: null
+
+paths:
+ .github/workflows/**/*.yml:
+ ignore:
+ - 1st argument of function call is not assignable
+ - SC2(015|038|086|091|097|098|129|155)
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index c8a3165d6903645..7f3376f8ddb1e25 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -12,6 +12,11 @@ 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:
@@ -19,3 +24,5 @@ updates:
labels:
- "skip issue"
- "skip news"
+ cooldown:
+ default-days: 14
diff --git a/.github/workflows/add-issue-header.yml b/.github/workflows/add-issue-header.yml
index 570b8779994a0f9..4c25976b9c24f72 100644
--- a/.github/workflows/add-issue-header.yml
+++ b/.github/workflows/add-issue-header.yml
@@ -12,14 +12,17 @@ on:
# Only ever run once
- opened
+permissions:
+ contents: read
jobs:
add-header:
runs-on: ubuntu-latest
permissions:
issues: write
+ timeout-minutes: 5
steps:
- - uses: actions/github-script@v7
+ - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
# language=JavaScript
script: |
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1b2677ff6fe8894..2159e06671e6c01 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,165 +1,166 @@
name: Tests
-# gh-84728: "paths-ignore" is not used to skip documentation-only PRs, because
-# it prevents to mark a job as mandatory. A PR cannot be merged if a job is
-# mandatory but not scheduled because of "paths-ignore".
on:
workflow_dispatch:
push:
branches:
- 'main'
- - '3.12'
- - '3.11'
- - '3.10'
- - '3.9'
- - '3.8'
+ - '3.*'
pull_request:
branches:
- 'main'
- - '3.12'
- - '3.11'
- - '3.10'
- - '3.9'
- - '3.8'
+ - '3.*'
permissions:
contents: read
concurrency:
- group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}-reusable
+ # https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency
+ # 'group' must be a key uniquely representing a PR or push event.
+ # github.workflow is the workflow name
+ # github.actor is the user invoking the workflow
+ # github.head_ref is the source branch of the PR or otherwise blank
+ # github.run_id is a unique number for the current run
+ group: ${{ github.workflow }}-${{ github.actor }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
+env:
+ FORCE_COLOR: 1
+
jobs:
- check_source:
- name: 'Check for source changes'
- runs-on: ubuntu-latest
- timeout-minutes: 10
- outputs:
- run-docs: ${{ steps.docs-changes.outputs.run-docs || false }}
- run_tests: ${{ steps.check.outputs.run_tests }}
- run_hypothesis: ${{ steps.check.outputs.run_hypothesis }}
- run_cifuzz: ${{ steps.check.outputs.run_cifuzz }}
- config_hash: ${{ steps.config_hash.outputs.hash }}
+ build-context:
+ name: Change detection
+ # To use boolean outputs from this job, parse them as JSON.
+ # Here's some examples:
+ #
+ # if: fromJSON(needs.build-context.outputs.run-docs)
+ #
+ # ${{
+ # fromJSON(needs.build-context.outputs.run-tests)
+ # && 'truthy-branch'
+ # || 'falsy-branch'
+ # }}
+ #
+ uses: ./.github/workflows/reusable-context.yml
+
+ check-docs:
+ name: Docs
+ needs: build-context
+ if: fromJSON(needs.build-context.outputs.run-docs)
+ uses: ./.github/workflows/reusable-docs.yml
+
+ check-abi:
+ name: 'Check if the ABI has changed'
+ runs-on: ubuntu-22.04 # 24.04 causes spurious errors
+ timeout-minutes: 30
+ needs: build-context
+ if: needs.build-context.outputs.run-tests == 'true'
steps:
- - uses: actions/checkout@v4
- - name: Check for source changes
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ - name: Install dependencies
+ run: |
+ sudo ./.github/workflows/posix-deps-apt.sh
+ sudo apt-get install -yq --no-install-recommends abigail-tools
+ - name: Build CPython
+ env:
+ CFLAGS: -g3 -O0
+ run: |
+ # Build Python with the libpython dynamic library
+ ./configure --enable-shared
+ make -j4
+ - name: Check for changes in the ABI
id: check
run: |
- if [ -z "$GITHUB_BASE_REF" ]; then
- echo "run_tests=true" >> $GITHUB_OUTPUT
- else
- git fetch origin $GITHUB_BASE_REF --depth=1
- # git diff "origin/$GITHUB_BASE_REF..." (3 dots) may be more
- # reliable than git diff "origin/$GITHUB_BASE_REF.." (2 dots),
- # but it requires to download more commits (this job uses
- # "git fetch --depth=1").
- #
- # git diff "origin/$GITHUB_BASE_REF..." (3 dots) works with Git
- # 2.26, but Git 2.28 is stricter and fails with "no merge base".
- #
- # git diff "origin/$GITHUB_BASE_REF.." (2 dots) should be enough on
- # GitHub, since GitHub starts by merging origin/$GITHUB_BASE_REF
- # into the PR branch anyway.
- #
- # https://github.com/python/core-workflow/issues/373
- git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc|^\.pre-commit-config\.yaml$|\.ruff\.toml$)' && echo "run_tests=true" >> $GITHUB_OUTPUT || true
- fi
-
- # Check if we should run hypothesis tests
- GIT_BRANCH=${GITHUB_BASE_REF:-${GITHUB_REF#refs/heads/}}
- echo $GIT_BRANCH
- if $(echo "$GIT_BRANCH" | grep -q -w '3\.\(8\|9\|10\|11\)'); then
- echo "Branch too old for hypothesis tests"
- echo "run_hypothesis=false" >> $GITHUB_OUTPUT
- else
- echo "Run hypothesis tests"
- echo "run_hypothesis=true" >> $GITHUB_OUTPUT
- fi
-
- # oss-fuzz maintains a configuration for fuzzing the main branch of
- # CPython, so CIFuzz should be run only for code that is likely to be
- # merged into the main branch; compatibility with older branches may
- # be broken.
- FUZZ_RELEVANT_FILES='(\.c$|\.h$|\.cpp$|^configure$|^\.github/workflows/build\.yml$|^Modules/_xxtestfuzz)'
- if [ "$GITHUB_BASE_REF" = "main" ] && [ "$(git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qE $FUZZ_RELEVANT_FILES; echo $?)" -eq 0 ]; then
- # The tests are pretty slow so they are executed only for PRs
- # changing relevant files.
- echo "Run CIFuzz tests"
- echo "run_cifuzz=true" >> $GITHUB_OUTPUT
- else
- echo "Branch too old for CIFuzz tests; or no C files were changed"
- echo "run_cifuzz=false" >> $GITHUB_OUTPUT
+ if ! make check-abidump; then
+ echo "Generated ABI file is not up to date."
+ echo "Please add the release manager of this branch as a reviewer of this PR."
+ echo ""
+ echo "The up to date ABI file should be attached to this build as an artifact."
+ echo ""
+ echo "To learn more about this check: https://devguide.python.org/getting-started/setup-building/index.html#regenerate-the-abi-dump"
+ echo ""
+ exit 1
fi
- - name: Compute hash for config cache key
- id: config_hash
+ - name: Generate updated ABI files
+ if: ${{ failure() && steps.check.conclusion == 'failure' }}
run: |
- echo "hash=${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }}" >> $GITHUB_OUTPUT
- - name: Get a list of the changed documentation-related files
- if: github.event_name == 'pull_request'
- id: changed-docs-files
- uses: Ana06/get-changed-files@v2.3.0
+ make regen-abidump
+ - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
+ name: Publish updated ABI files
+ if: ${{ failure() && steps.check.conclusion == 'failure' }}
with:
- filter: |
- Doc/**
- Misc/**
- .github/workflows/reusable-docs.yml
- format: csv # works for paths with spaces
- - name: Check for docs changes
- if: >-
- github.event_name == 'pull_request'
- && steps.changed-docs-files.outputs.added_modified_renamed != ''
- id: docs-changes
- run: |
- echo "run-docs=true" >> "${GITHUB_OUTPUT}"
+ name: abi-data
+ path: ./Doc/data/*.abi
- check-docs:
- name: Docs
- needs: check_source
- if: fromJSON(needs.check_source.outputs.run-docs)
- uses: ./.github/workflows/reusable-docs.yml
-
- check_generated_files:
- name: 'Check if generated files are up to date'
+ check-autoconf-regen:
+ name: 'Check if Autoconf files are up to date'
# Don't use ubuntu-latest but a specific version to make the job
# reproducible: to get the same tools versions (autoconf, aclocal, ...)
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
+ container:
+ image: ghcr.io/python/autoconf:2024.10.16.11360930377
timeout-minutes: 60
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true'
+ needs: build-context
+ if: needs.build-context.outputs.run-tests == 'true'
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-python@v5
- with:
- python-version: '3.x'
- - name: Runner image version
- run: echo "IMAGE_VERSION=${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 }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.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
+ - name: Install Git
+ run: |
+ apt update && apt install git -yq
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
- save: false
+ fetch-depth: 1
+ persist-credentials: false
- name: Check Autoconf and aclocal versions
run: |
grep "Generated by GNU Autoconf 2.71" configure
grep "aclocal 1.16.5" aclocal.m4
grep -q "runstatedir" configure
grep -q "PKG_PROG_PKG_CONFIG" aclocal.m4
+ - name: Regenerate autoconf files
+ # Same command used by Tools/build/regen-configure.sh ($AUTORECONF)
+ run: autoreconf -ivf -Werror
+ - name: Check for changes
+ run: |
+ git add -u
+ changes=$(git status --porcelain)
+ # Check for changes in regenerated files
+ if test -n "$changes"; then
+ echo "Generated files not up to date."
+ echo "Perhaps you forgot to run make regen-configure ;)"
+ echo "configure files must be regenerated with a specific version of autoconf."
+ echo "$changes"
+ echo ""
+ git diff --staged || true
+ exit 1
+ fi
+
+ check-generated-files:
+ name: 'Check if generated files are up to date'
+ # Don't use ubuntu-latest but a specific version to make the job
+ # reproducible: to get the same tools versions (autoconf, aclocal, ...)
+ runs-on: ubuntu-24.04
+ timeout-minutes: 60
+ needs: build-context
+ if: needs.build-context.outputs.run-tests == 'true'
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ with:
+ python-version: '3.x'
+ - name: Runner image version
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
+ - name: Install dependencies
+ run: sudo ./.github/workflows/posix-deps-apt.sh
- name: Configure CPython
run: |
# Build Python with the libpython dynamic library
./configure --config-cache --with-pydebug --enable-shared
- - name: Regenerate autoconf files
- # Same command used by Tools/build/regen-configure.sh ($AUTORECONF)
- run: autoreconf -ivf -Werror
- name: Build CPython
run: |
make -j4 regen-all
@@ -186,117 +187,153 @@ jobs:
if: github.event_name == 'pull_request' # $GITHUB_EVENT_NAME
run: make check-c-globals
- build_windows:
- name: 'Windows'
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true'
- uses: ./.github/workflows/reusable-windows.yml
+ check-c-api-docs:
+ name: C API Docs
+ needs: build-context
+ if: >-
+ needs.build-context.outputs.run-tests == 'true'
+ || needs.build-context.outputs.run-docs == 'true'
+ uses: ./.github/workflows/reusable-check-c-api-docs.yml
- build_windows_free_threading:
- name: 'Windows (free-threading)'
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true'
+ build-windows:
+ name: >-
+ Windows
+ ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
+ needs: build-context
+ if: fromJSON(needs.build-context.outputs.run-windows-tests)
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+ - windows-2022
+ arch:
+ - x64
+ free-threading:
+ - false
+ - true
+ include:
+ - os: windows-2022 # FIXME(diegorusso): change to os: windows-aarch64
+ arch: arm64
+ free-threading: false
+ - os: windows-2022 # FIXME(diegorusso): change to os: windows-aarch64
+ arch: arm64
+ free-threading: true
+ - os: windows-2022
+ arch: Win32
+ free-threading: false
uses: ./.github/workflows/reusable-windows.yml
with:
- free-threading: true
+ os: ${{ matrix.os }}
+ arch: ${{ matrix.arch }}
+ free-threading: ${{ matrix.free-threading }}
- build_macos:
- name: 'macOS'
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true'
- uses: ./.github/workflows/reusable-macos.yml
+ build-windows-msi:
+ # ${{ '' } is a hack to nest jobs under the same sidebar category.
+ name: Windows MSI${{ '' }} # zizmor: ignore[obfuscation]
+ needs: build-context
+ if: fromJSON(needs.build-context.outputs.run-windows-msi)
+ strategy:
+ fail-fast: false
+ matrix:
+ arch:
+ - x86
+ - x64
+ - arm64
+ uses: ./.github/workflows/reusable-windows-msi.yml
with:
- config_hash: ${{ needs.check_source.outputs.config_hash }}
- # macos-14 is M1, macos-13 is Intel
- os-matrix: '["macos-14", "macos-13"]'
+ arch: ${{ matrix.arch }}
- build_macos_free_threading:
- name: 'macOS (free-threading)'
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true'
+ build-macos:
+ name: >-
+ macOS
+ ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
+ needs: build-context
+ if: needs.build-context.outputs.run-macos == 'true'
+ strategy:
+ fail-fast: false
+ matrix:
+ # macos-26 is Apple Silicon, macos-26-intel is Intel.
+ # macos-26-intel only runs tests against the GIL-enabled CPython.
+ os:
+ - macos-26
+ - macos-26-intel
+ free-threading:
+ - false
+ - true
+ exclude:
+ - os: macos-26-intel
+ free-threading: true
uses: ./.github/workflows/reusable-macos.yml
with:
- config_hash: ${{ needs.check_source.outputs.config_hash }}
- free-threading: true
- # macos-14-large is Intel with 12 cores (most parallelism)
- os-matrix: '["macos-14"]'
+ free-threading: ${{ matrix.free-threading }}
+ os: ${{ matrix.os }}
- build_ubuntu:
- name: 'Ubuntu'
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true'
+ build-ubuntu:
+ name: >-
+ Ubuntu
+ ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
+ needs: build-context
+ if: needs.build-context.outputs.run-ubuntu == 'true'
+ strategy:
+ fail-fast: false
+ matrix:
+ free-threading:
+ - false
+ - true
uses: ./.github/workflows/reusable-ubuntu.yml
with:
- config_hash: ${{ needs.check_source.outputs.config_hash }}
- options: |
- ../cpython-ro-srcdir/configure \
- --config-cache \
- --with-pydebug \
- --with-openssl=$OPENSSL_DIR
+ free-threading: ${{ matrix.free-threading }}
- build_ubuntu_free_threading:
- name: 'Ubuntu (free-threading)'
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true'
- uses: ./.github/workflows/reusable-ubuntu.yml
- with:
- config_hash: ${{ needs.check_source.outputs.config_hash }}
- options: |
- ../cpython-ro-srcdir/configure \
- --config-cache \
- --with-pydebug \
- --with-openssl=$OPENSSL_DIR \
- --disable-gil
+ build-ubuntu-installed:
+ name: 'Ubuntu (installed)'
+ needs: build-context
+ if: needs.build-context.outputs.run-ubuntu == 'true'
+ uses: ./.github/workflows/reusable-install.yml
- build_ubuntu_ssltests:
+ build-ubuntu-ssltests:
name: 'Ubuntu SSL tests with OpenSSL'
- runs-on: ubuntu-22.04
+ runs-on: ${{ matrix.os }}
timeout-minutes: 60
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true'
+ needs: build-context
+ if: needs.build-context.outputs.run-ubuntu == 'true'
strategy:
fail-fast: false
matrix:
- openssl_ver: [1.1.1w, 3.0.13, 3.1.5, 3.2.1]
+ os: [ubuntu-24.04]
+ # Keep 1.1.1w in our list despite it being upstream EOL and otherwise
+ # unsupported as it most resembles other 1.1.1-work-a-like ssl APIs
+ # supported by important vendors such as AWS-LC.
+ openssl_ver: [1.1.1w, 3.0.22, 3.4.7, 3.5.8, 3.6.4]
+ # See Tools/ssl/make_ssl_data.py for notes on adding a new version
env:
OPENSSL_VER: ${{ matrix.openssl_ver }}
MULTISSL_DIR: ${{ github.workspace }}/multissl
OPENSSL_DIR: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}
LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}/lib
steps:
- - uses: actions/checkout@v4
- - name: Runner image version
- run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
- - name: Restore config.cache
- uses: actions/cache@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
- path: config.cache
- key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.outputs.config_hash }}
+ persist-credentials: false
+ - name: Runner image version
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- - name: Install Dependencies
+ - name: Install dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: Configure OpenSSL env vars
run: |
- echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV
- echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV
- echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV
+ echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV"
+ echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV"
+ echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
- name: 'Restore OpenSSL build'
id: cache-openssl
- uses: actions/cache@v4
+ uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
- key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
+ key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
- name: Install OpenSSL
if: steps.cache-openssl.outputs.cache-hit != 'true'
- run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux
- - name: Add ccache to PATH
- run: |
- echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
- - name: Configure ccache action
- uses: hendrikmuhs/ccache-action@v1.2
- with:
- save: false
+ run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux
- name: Configure CPython
run: ./configure --config-cache --with-pydebug --with-openssl=$OPENSSL_DIR
- name: Build CPython
@@ -306,72 +343,82 @@ jobs:
- name: SSL tests
run: ./python Lib/test/ssltests.py
- build_wasi:
+ build-android:
+ name: Android (${{ matrix.arch }})
+ needs: build-context
+ if: needs.build-context.outputs.run-android == 'true'
+ timeout-minutes: 60
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - arch: aarch64
+ runs-on: macos-26
+ - arch: x86_64
+ runs-on: ubuntu-24.04
+
+ runs-on: ${{ matrix.runs-on }}
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - name: Build and test
+ run: ./Android/android.py ci --fast-ci ${{ matrix.arch }}-linux-android
+
+ build-wasi:
name: 'WASI'
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true'
+ needs: build-context
+ if: needs.build-context.outputs.run-wasi == 'true'
uses: ./.github/workflows/reusable-wasi.yml
- with:
- config_hash: ${{ needs.check_source.outputs.config_hash }}
- test_hypothesis:
+ test-hypothesis:
name: "Hypothesis tests on Ubuntu"
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
timeout-minutes: 60
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_hypothesis == 'true'
+ needs: build-context
+ if: needs.build-context.outputs.run-ubuntu == 'true'
env:
- OPENSSL_VER: 3.0.13
+ OPENSSL_VER: 3.0.22
PYTHONSTRICTEXTENSIONBUILD: 1
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
- name: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- - name: Install Dependencies
+ - name: Install dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: Configure OpenSSL env vars
run: |
- echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV
- echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV
- echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV
+ echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV"
+ echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV"
+ echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
- name: 'Restore OpenSSL build'
id: cache-openssl
- uses: actions/cache@v4
+ uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
- name: Install OpenSSL
if: steps.cache-openssl.outputs.cache-hit != 'true'
run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux
- - name: Add ccache to PATH
- run: |
- echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
- - name: 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
- echo "CPYTHON_BUILDDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-builddir)" >> $GITHUB_ENV
+ echo "CPYTHON_RO_SRCDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-ro-srcdir)" >> "$GITHUB_ENV"
+ echo "CPYTHON_BUILDDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-builddir)" >> "$GITHUB_ENV"
- name: Create directories for read-only out-of-tree builds
- run: mkdir -p $CPYTHON_RO_SRCDIR $CPYTHON_BUILDDIR
+ run: mkdir -p "$CPYTHON_RO_SRCDIR" "$CPYTHON_BUILDDIR"
- name: Bind mount sources read-only
- run: sudo mount --bind -o ro $GITHUB_WORKSPACE $CPYTHON_RO_SRCDIR
+ run: sudo mount --bind -o ro "$GITHUB_WORKSPACE" "$CPYTHON_RO_SRCDIR"
- name: Runner image version
- run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
- - name: Restore config.cache
- uses: actions/cache@v4
- with:
- path: ${{ env.CPYTHON_BUILDDIR }}/config.cache
- key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.outputs.config_hash }}
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Configure CPython out-of-tree
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: |
../cpython-ro-srcdir/configure \
--config-cache \
--with-pydebug \
- --with-openssl=$OPENSSL_DIR
+ --with-openssl="$OPENSSL_DIR"
- name: Build CPython out-of-tree
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: make -j4
@@ -380,26 +427,26 @@ jobs:
run: make pythoninfo
- name: Remount sources writable for tests
# some tests write to srcdir, lack of pyc files slows down testing
- run: sudo mount $CPYTHON_RO_SRCDIR -oremount,rw
+ run: sudo mount "$CPYTHON_RO_SRCDIR" -oremount,rw
- name: Setup directory envs for out-of-tree builds
run: |
- echo "CPYTHON_BUILDDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-builddir)" >> $GITHUB_ENV
+ echo "CPYTHON_BUILDDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-builddir)" >> "$GITHUB_ENV"
- name: "Create hypothesis venv"
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: |
VENV_LOC=$(realpath -m .)/hypovenv
VENV_PYTHON=$VENV_LOC/bin/python
- echo "HYPOVENV=${VENV_LOC}" >> $GITHUB_ENV
- echo "VENV_PYTHON=${VENV_PYTHON}" >> $GITHUB_ENV
- ./python -m venv $VENV_LOC && $VENV_PYTHON -m pip install -r ${GITHUB_WORKSPACE}/Tools/requirements-hypothesis.txt
+ echo "HYPOVENV=${VENV_LOC}" >> "$GITHUB_ENV"
+ echo "VENV_PYTHON=${VENV_PYTHON}" >> "$GITHUB_ENV"
+ ./python -m venv "$VENV_LOC" && "$VENV_PYTHON" -m pip install -r "${GITHUB_WORKSPACE}/Tools/requirements-hypothesis.txt"
- name: 'Restore Hypothesis database'
id: cache-hypothesis-database
- uses: actions/cache@v4
+ uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
- path: ./hypothesis
+ path: ${{ env.CPYTHON_BUILDDIR }}/.hypothesis/
key: hypothesis-database-${{ github.head_ref || github.run_id }}
restore-keys: |
- - hypothesis-database-
+ hypothesis-database-
- name: "Run tests"
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: |
@@ -407,10 +454,11 @@ jobs:
#
# (GH-104097) test_sysconfig is skipped because it has tests that are
# failing when executed from inside a virtual environment.
- ${{ env.VENV_PYTHON }} -m test \
+ "${VENV_PYTHON}" -m test \
-W \
- -o \
+ --slowest \
-j4 \
+ --timeout 900 \
-x test_asyncio \
-x test_multiprocessing_fork \
-x test_multiprocessing_forkserver \
@@ -420,62 +468,50 @@ jobs:
-x test_subprocess \
-x test_signal \
-x test_sysconfig
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
if: always()
with:
name: hypothesis-example-db
- path: .hypothesis/examples/
-
+ path: ${{ env.CPYTHON_BUILDDIR }}/.hypothesis/examples/
- build_asan:
+ build-asan:
name: 'Address sanitizer'
- runs-on: ubuntu-22.04
+ runs-on: ${{ matrix.os }}
timeout-minutes: 60
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true'
+ needs: build-context
+ if: needs.build-context.outputs.run-ubuntu == 'true'
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-24.04]
env:
- OPENSSL_VER: 3.0.13
+ OPENSSL_VER: 3.0.22
PYTHONSTRICTEXTENSIONBUILD: 1
ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
steps:
- - uses: actions/checkout@v4
- - name: Runner image version
- run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
- - name: Restore config.cache
- uses: actions/cache@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
- path: config.cache
- key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.outputs.config_hash }}
+ persist-credentials: false
+ - name: Runner image version
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- - name: Install Dependencies
+ - name: Install dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- - name: Set up GCC-10 for ASAN
- uses: egor-tensin/setup-gcc@v1
- with:
- version: 10
- name: Configure OpenSSL env vars
run: |
- echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV
- echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV
- echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV
+ echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV"
+ echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV"
+ echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
- name: 'Restore OpenSSL build'
id: cache-openssl
- uses: actions/cache@v4
+ uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
- key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
+ key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
- name: Install OpenSSL
if: steps.cache-openssl.outputs.cache-hit != 'true'
- run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux
- - name: Add ccache to PATH
- run: |
- echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
- - name: Configure ccache action
- uses: hendrikmuhs/ccache-action@v1.2
- with:
- save: ${{ github.event_name == 'push' }}
- max-size: "200M"
+ run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux
- name: Configure CPython
run: ./configure --config-cache --with-address-sanitizer --without-pymalloc
- name: Build CPython
@@ -485,136 +521,139 @@ jobs:
- name: Tests
run: xvfb-run make test
- build_tsan:
- name: 'Thread sanitizer'
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true'
- uses: ./.github/workflows/reusable-tsan.yml
- with:
- config_hash: ${{ needs.check_source.outputs.config_hash }}
- options: ./configure --config-cache --with-thread-sanitizer --with-pydebug
- suppressions_path: Tools/tsan/supressions.txt
-
- build_tsan_free_threading:
- name: 'Thread sanitizer (free-threading)'
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true'
- uses: ./.github/workflows/reusable-tsan.yml
+ build-san:
+ # ${{ '' } 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'
+ strategy:
+ fail-fast: false
+ matrix:
+ check-name:
+ - Thread
+ free-threading:
+ - false
+ - true
+ sanitizer:
+ - TSan
+ uses: ./.github/workflows/reusable-san.yml
with:
- config_hash: ${{ needs.check_source.outputs.config_hash }}
- options: ./configure --config-cache --disable-gil --with-thread-sanitizer --with-pydebug
- suppressions_path: Tools/tsan/suppressions_free_threading.txt
+ sanitizer: ${{ matrix.sanitizer }}
+ free-threading: ${{ matrix.free-threading }}
- # CIFuzz job based on https://google.github.io/oss-fuzz/getting-started/continuous-integration/
cifuzz:
- name: CIFuzz
- runs-on: ubuntu-latest
- timeout-minutes: 60
- needs: check_source
- if: needs.check_source.outputs.run_cifuzz == 'true'
+ # ${{ '' } is a hack to nest jobs under the same sidebar category.
+ name: CIFuzz${{ '' }} # zizmor: ignore[obfuscation]
+ needs: build-context
+ if: >-
+ needs.build-context.outputs.run-ci-fuzz == 'true'
+ || needs.build-context.outputs.run-ci-fuzz-stdlib == 'true'
permissions:
+ contents: read
security-events: write
strategy:
fail-fast: false
matrix:
- sanitizer: [address, undefined, memory]
- steps:
- - name: Build fuzzers (${{ matrix.sanitizer }})
- id: build
- uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
- with:
- oss-fuzz-project-name: cpython3
- sanitizer: ${{ matrix.sanitizer }}
- - name: Run fuzzers (${{ matrix.sanitizer }})
- uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
- with:
- fuzz-seconds: 600
- oss-fuzz-project-name: cpython3
- output-sarif: true
- sanitizer: ${{ matrix.sanitizer }}
- - name: Upload crash
- uses: actions/upload-artifact@v4
- if: failure() && steps.build.outcome == 'success'
- with:
- name: ${{ matrix.sanitizer }}-artifacts
- path: ./out/artifacts
- - name: Upload SARIF
- if: always() && steps.build.outcome == 'success'
- uses: github/codeql-action/upload-sarif@v3
- with:
- sarif_file: cifuzz-sarif/results.sarif
- checkout_path: cifuzz-sarif
+ sanitizer:
+ - address
+ oss-fuzz-project-name:
+ - cpython3
+ - python3-libraries
+ include:
+ - sanitizer: undefined
+ oss-fuzz-project-name: cpython3
+ - sanitizer: memory
+ oss-fuzz-project-name: cpython3
+ exclude:
+ # Note that the 'no-exclude' sentinel below is to prevent
+ # an empty string value from excluding all jobs and causing
+ # GHA to create a 'default' matrix entry with all empty values.
+ - oss-fuzz-project-name: >-
+ ${{
+ needs.build-context.outputs.run-ci-fuzz == 'true'
+ && 'no-exclude'
+ || 'cpython3'
+ }}
+ - oss-fuzz-project-name: >-
+ ${{
+ needs.build-context.outputs.run-ci-fuzz-stdlib == 'true'
+ && 'no-exclude'
+ || 'python3-libraries'
+ }}
+ uses: ./.github/workflows/reusable-cifuzz.yml
+ with:
+ oss-fuzz-project-name: ${{ matrix.oss-fuzz-project-name }}
+ sanitizer: ${{ matrix.sanitizer }}
all-required-green: # This job does nothing and is only used for the branch protection
name: All required checks pass
- if: always()
-
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
needs:
- - check_source # Transitive dependency, needed to access `run_tests` value
+ - build-context # Transitive dependency, needed to access `run-tests` value
- check-docs
- - check_generated_files
- - build_macos
- - build_macos_free_threading
- - build_ubuntu
- - build_ubuntu_free_threading
- - build_ubuntu_ssltests
- - build_wasi
- - build_windows
- - build_windows_free_threading
- - test_hypothesis
- - build_asan
- - build_tsan
- - build_tsan_free_threading
+ - check-autoconf-regen
+ - check-generated-files
+ - check-c-api-docs
+ - build-windows
+ - build-windows-msi
+ - build-macos
+ - build-ubuntu
+ - build-ubuntu-installed
+ - build-ubuntu-ssltests
+ - build-wasi
+ - test-hypothesis
+ - build-asan
+ - build-san
- cifuzz
-
- runs-on: ubuntu-latest
+ if: always()
steps:
- name: Check whether the needed jobs succeeded or failed
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe
with:
allowed-failures: >-
- build_ubuntu_ssltests,
+ build-android,
+ build-windows-msi,
+ build-ubuntu-ssltests,
+ test-hypothesis,
cifuzz,
- test_hypothesis,
allowed-skips: >-
+ ${{ !fromJSON(needs.build-context.outputs.run-docs) && 'check-docs,' || '' }}
${{
- !fromJSON(needs.check_source.outputs.run-docs)
+ needs.build-context.outputs.run-tests != 'true'
&& '
- check-docs,
+ check-autoconf-regen,
+ check-generated-files,
'
|| ''
}}
${{
- needs.check_source.outputs.run_tests != 'true'
- && '
- check_generated_files,
- build_macos,
- build_macos_free_threading,
- build_ubuntu,
- build_ubuntu_free_threading,
- build_ubuntu_ssltests,
- build_wasi,
- build_windows,
- build_windows_free_threading,
- build_asan,
- build_tsan,
- build_tsan_free_threading,
- '
+ !fromJSON(needs.build-context.outputs.run-tests)
+ && !fromJSON(needs.build-context.outputs.run-docs)
+ && 'check-c-api-docs,'
|| ''
}}
+ ${{ !fromJSON(needs.build-context.outputs.run-windows-tests) && 'build-windows,' || '' }}
${{
- !fromJSON(needs.check_source.outputs.run_cifuzz)
- && '
- cifuzz,
- '
- || ''
+ !fromJSON(needs.build-context.outputs.run-ci-fuzz)
+ && !fromJSON(needs.build-context.outputs.run-ci-fuzz-stdlib)
+ && 'cifuzz,' ||
+ ''
}}
+ ${{ !fromJSON(needs.build-context.outputs.run-macos) && 'build-macos,' || '' }}
${{
- !fromJSON(needs.check_source.outputs.run_hypothesis)
+ !fromJSON(needs.build-context.outputs.run-ubuntu)
&& '
- test_hypothesis,
+ build-ubuntu,
+ build-ubuntu-installed,
+ build-ubuntu-ssltests,
+ test-hypothesis,
+ build-asan,
+ build-san,
'
|| ''
}}
+ ${{ !fromJSON(needs.build-context.outputs.run-android) && 'build-android,' || '' }}
+ ${{ !fromJSON(needs.build-context.outputs.run-wasi) && 'build-wasi,' || '' }}
jobs: ${{ toJSON(needs) }}
diff --git a/.github/workflows/build_msi.yml b/.github/workflows/build_msi.yml
deleted file mode 100644
index 65d32c734e77455..000000000000000
--- a/.github/workflows/build_msi.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-name: TestsMSI
-
-on:
- workflow_dispatch:
- push:
- branches:
- - 'main'
- - '3.*'
- paths:
- - 'Tools/msi/**'
- - '.github/workflows/build_msi.yml'
- pull_request:
- branches:
- - 'main'
- - '3.*'
- paths:
- - 'Tools/msi/**'
- - '.github/workflows/build_msi.yml'
-
-permissions:
- contents: read
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
- cancel-in-progress: true
-
-jobs:
- build:
- name: Windows Installer
- runs-on: windows-latest
- timeout-minutes: 60
- strategy:
- matrix:
- type: [x86, x64, arm64]
- env:
- IncludeFreethreaded: true
- steps:
- - uses: actions/checkout@v4
- - name: Build CPython installer
- run: .\Tools\msi\build.bat --doc -${{ matrix.type }}
diff --git a/.github/workflows/documentation-links.yml b/.github/workflows/documentation-links.yml
deleted file mode 100644
index 43a7afec73884e8..000000000000000
--- a/.github/workflows/documentation-links.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-name: Read the Docs PR preview
-# Automatically edits a pull request's descriptions with a link
-# to the documentation's preview on Read the Docs.
-
-on:
- pull_request_target:
- types:
- - opened
- paths:
- - 'Doc/**'
- - '.github/workflows/doc.yml'
-
-permissions:
- pull-requests: write
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
- cancel-in-progress: true
-
-jobs:
- documentation-links:
- runs-on: ubuntu-latest
- steps:
- - uses: readthedocs/actions/preview@v1
- with:
- project-slug: "cpython-previews"
- single-version: "true"
diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml
index 7152cde8f4607c8..ba26379bc8cb1ef 100644
--- a/.github/workflows/jit.yml
+++ b/.github/workflows/jit.yml
@@ -5,11 +5,17 @@ on:
- '**jit**'
- 'Python/bytecodes.c'
- 'Python/optimizer*.c'
+ - '!Python/perf_jit_trampoline.c'
+ - '!**/*.md'
+ - '!**/*.ini'
push:
paths:
- '**jit**'
- 'Python/bytecodes.c'
- 'Python/optimizer*.c'
+ - '!Python/perf_jit_trampoline.c'
+ - '!**/*.md'
+ - '!**/*.ini'
workflow_dispatch:
permissions:
@@ -19,9 +25,28 @@ concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
+env:
+ FORCE_COLOR: 1
+
jobs:
+ interpreter:
+ name: Interpreter (Debug)
+ runs-on: ubuntu-latest
+ timeout-minutes: 90
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - name: Build tier two interpreter
+ run: |
+ ./configure --enable-experimental-jit=interpreter --with-pydebug
+ make all --jobs 4
+ - name: Test tier two interpreter
+ run: |
+ ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
jit:
name: ${{ matrix.target }} (${{ matrix.debug && 'Debug' || 'Release' }})
+ needs: interpreter
runs-on: ${{ matrix.runner }}
timeout-minutes: 90
strategy:
@@ -45,23 +70,23 @@ jobs:
include:
- target: i686-pc-windows-msvc/msvc
architecture: Win32
- runner: windows-latest
+ runner: windows-2022
compiler: msvc
- target: x86_64-pc-windows-msvc/msvc
architecture: x64
- runner: windows-latest
+ runner: windows-2022
compiler: msvc
- target: aarch64-pc-windows-msvc/msvc
architecture: ARM64
- runner: windows-latest
+ runner: windows-2022
compiler: msvc
- target: x86_64-apple-darwin/clang
architecture: x86_64
- runner: macos-13
+ runner: macos-26-intel
compiler: clang
- target: aarch64-apple-darwin/clang
architecture: aarch64
- runner: macos-14
+ runner: macos-26
compiler: clang
- target: x86_64-unknown-linux-gnu/gcc
architecture: x86_64
@@ -82,16 +107,17 @@ jobs:
env:
CC: ${{ matrix.compiler }}
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-python@v5
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.11'
- name: Native Windows
if: runner.os == 'Windows' && matrix.architecture != 'ARM64'
run: |
- choco upgrade llvm -y
- choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}
+ choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '--pgo' }} -p ${{ matrix.architecture }}
./PCbuild/rt.bat ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
@@ -99,8 +125,7 @@ jobs:
- name: Emulated Windows
if: runner.os == 'Windows' && matrix.architecture == 'ARM64'
run: |
- choco upgrade llvm -y
- choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}
+ choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }}
- name: Native macOS
@@ -108,22 +133,20 @@ jobs:
run: |
brew update
brew install llvm@${{ matrix.llvm }}
- SDKROOT="$(xcrun --show-sdk-path)" \
- ./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '--enable-optimizations --with-lto' }}
+ export SDKROOT="$(xcrun --show-sdk-path)"
+ ./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '--enable-optimizations --with-lto' }}
make all --jobs 4
./python.exe -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
- # --with-lto has been removed temporarily as a result of an open issue in LLVM 18 (see https://github.com/llvm/llvm-project/issues/87553)
- name: Native Linux
if: runner.os == 'Linux' && matrix.architecture == 'x86_64'
run: |
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH"
- ./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '--enable-optimizations' }}
+ ./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '--enable-optimizations --with-lto' }}
make all --jobs 4
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
- # --with-lto has been removed temporarily as a result of an open issue in LLVM 18 (see https://github.com/llvm/llvm-project/issues/87553)
- name: Emulated Linux
if: runner.os == 'Linux' && matrix.architecture != 'x86_64'
# The --ignorefile on ./python -m test is used to exclude tests known to fail when running on an emulated Linux.
@@ -141,6 +164,28 @@ jobs:
CC="${{ matrix.compiler == 'clang' && 'clang --target=$HOST' || '$HOST-gcc' }}" \
CPP="$CC --preprocess" \
HOSTRUNNER=qemu-${{ matrix.architecture }} \
- ./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '--enable-optimizations ' }} --build=x86_64-linux-gnu --host="$HOST" --with-build-python=../build/bin/python3 --with-pkg-config=no ac_cv_buggy_getaddrinfo=no ac_cv_file__dev_ptc=no ac_cv_file__dev_ptmx=yes
+ ./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '--enable-optimizations --with-lto' }} --build=x86_64-linux-gnu --host="$HOST" --with-build-python=../build/bin/python3 --with-pkg-config=no ac_cv_buggy_getaddrinfo=no ac_cv_file__dev_ptc=no ac_cv_file__dev_ptmx=yes
make all --jobs 4
./python -m test --ignorefile=Tools/jit/ignore-tests-emulated-linux.txt --multiprocess 0 --timeout 4500 --verbose2 --verbose3
+
+ jit-with-disabled-gil:
+ name: Free-Threaded (Debug)
+ needs: interpreter
+ runs-on: ubuntu-latest
+ timeout-minutes: 90
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ with:
+ python-version: '3.11'
+ - name: Build with JIT enabled and GIL disabled
+ run: |
+ sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh 18
+ export PATH="$(llvm-config-18 --bindir):$PATH"
+ ./configure --enable-experimental-jit --with-pydebug --disable-gil
+ make all --jobs 4
+ - name: Run tests
+ run: |
+ ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index ccde03f91983df0..e9a4eb2b0808cb7 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -19,8 +19,7 @@ jobs:
timeout-minutes: 10
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-python@v5
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
- python-version: "3.x"
- - uses: pre-commit/action@v3.0.1
+ persist-credentials: false
+ - uses: j178/prek-action@0bb87d7f00b0c99306c8bcb8b8beba1eb581c037 # v1.1.1
diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml
index 35996f237814baf..60d0a592fee0b31 100644
--- a/.github/workflows/mypy.yml
+++ b/.github/workflows/mypy.yml
@@ -8,15 +8,26 @@ on:
pull_request:
paths:
- ".github/workflows/mypy.yml"
+ - "Lib/_colorize.py"
- "Lib/_pyrepl/**"
- "Lib/test/libregrtest/**"
+ - "Lib/tomllib/**"
+ - "Misc/mypy/**"
+ - "Tools/build/mypy.ini"
+ - "Tools/build/check_extension_modules.py"
+ - "Tools/build/compute-changes.py"
+ - "Tools/build/deepfreeze.py"
- "Tools/build/generate_sbom.py"
+ - "Tools/build/generate_stdlib_module_names.py"
+ - "Tools/build/verify_ensurepip_wheels.py"
+ - "Tools/build/update_file.py"
+ - "Tools/build/umarshal.py"
- "Tools/cases_generator/**"
+ - "Tools/check-c-api-docs/**"
- "Tools/clinic/**"
- "Tools/jit/**"
- "Tools/peg_generator/**"
- "Tools/requirements-dev.txt"
- - "Tools/wasm/**"
workflow_dispatch:
permissions:
@@ -33,27 +44,32 @@ concurrency:
jobs:
mypy:
+ name: Run mypy on ${{ matrix.target }}
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
strategy:
+ fail-fast: false
matrix:
target: [
"Lib/_pyrepl",
"Lib/test/libregrtest",
+ "Lib/tomllib",
"Tools/build",
"Tools/cases_generator",
+ "Tools/check-c-api-docs",
"Tools/clinic",
"Tools/jit",
"Tools/peg_generator",
- "Tools/wasm",
]
- name: Run mypy on ${{ matrix.target }}
- runs-on: ubuntu-latest
- timeout-minutes: 10
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-python@v5
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
- python-version: "3.11"
- cache: pip
- cache-dependency-path: Tools/requirements-dev.txt
- - run: pip install -r Tools/requirements-dev.txt
- - run: mypy --config-file ${{ matrix.target }}/mypy.ini
+ python-version: "3.13"
+ activate-environment: true
+ cache-dependency-glob: Tools/requirements-dev.txt
+ - run: uv pip install -r Tools/requirements-dev.txt
+ - run: python3 Misc/mypy/make_symlinks.py --symlink
+ - run: mypy --num-workers 4 --config-file ${{ matrix.target }}/mypy.ini
diff --git a/.github/workflows/new-bugs-announce-notifier.yml b/.github/workflows/new-bugs-announce-notifier.yml
index 9f1a8a824e5f19a..e585657dde68816 100644
--- a/.github/workflows/new-bugs-announce-notifier.yml
+++ b/.github/workflows/new-bugs-announce-notifier.yml
@@ -6,19 +6,21 @@ on:
- opened
permissions:
- issues: read
+ contents: read
jobs:
notify-new-bugs-announce:
runs-on: ubuntu-latest
+ permissions:
+ issues: read
timeout-minutes: 10
steps:
- - uses: actions/setup-node@v4
+ - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 20
- run: npm install mailgun.js form-data
- name: Send notification
- uses: actions/github-script@v7
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
MAILGUN_API_KEY: ${{ secrets.MAILGUN_PYTHON_ORG_MAILGUN_KEY }}
with:
diff --git a/.github/workflows/posix-deps-apt.sh b/.github/workflows/posix-deps-apt.sh
index fb485bd4f82bd2f..69de368f5d7b61c 100755
--- a/.github/workflows/posix-deps-apt.sh
+++ b/.github/workflows/posix-deps-apt.sh
@@ -1,12 +1,9 @@
#!/bin/sh
apt-get update
-# autoconf-archive is needed by autoreconf (check_generated_files job)
-apt-get -yq install \
+apt-get -yq --no-install-recommends install \
build-essential \
pkg-config \
- autoconf-archive \
- ccache \
gdb \
lcov \
libb2-dev \
@@ -15,7 +12,6 @@ apt-get -yq install \
libgdbm-dev \
libgdbm-compat-dev \
liblzma-dev \
- libmpdec-dev \
libncurses5-dev \
libreadline6-dev \
libsqlite3-dev \
diff --git a/.github/workflows/project-updater.yml b/.github/workflows/project-updater.yml
index 066d8593a70cf62..710424a28f2824b 100644
--- a/.github/workflows/project-updater.yml
+++ b/.github/workflows/project-updater.yml
@@ -15,6 +15,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
+ fail-fast: false
matrix:
include:
# if an issue has any of these labels, it will be added
@@ -23,7 +24,7 @@ jobs:
- { project: 32, label: sprint }
steps:
- - uses: actions/add-to-project@v1.0.0
+ - uses: actions/add-to-project@244f685bbc3b7adfa8466e08b698b5577571133e # v1.0.2
with:
project-url: https://github.com/orgs/python/projects/${{ matrix.project }}
github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}
diff --git a/.github/workflows/regen-abidump.sh b/.github/workflows/regen-abidump.sh
index 251bb3857ecfcb6..75a1a72e3702024 100644
--- a/.github/workflows/regen-abidump.sh
+++ b/.github/workflows/regen-abidump.sh
@@ -2,7 +2,7 @@ set -ex
export DEBIAN_FRONTEND=noninteractive
./.github/workflows/posix-deps-apt.sh
-apt-get install -yq abigail-tools python3
+apt-get install -yq --no-install-recommends abigail-tools python3
export CFLAGS="-g3 -O0"
./configure --enable-shared && make
make regen-abidump
diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml
index ff5cbdf3eda749a..206f24cf9d5fb32 100644
--- a/.github/workflows/require-pr-label.yml
+++ b/.github/workflows/require-pr-label.yml
@@ -5,18 +5,19 @@ on:
types: [opened, reopened, labeled, unlabeled, synchronize]
permissions:
- issues: write
- pull-requests: write
+ contents: read
jobs:
label:
name: DO-NOT-MERGE / unresolved review
if: github.repository_owner == 'python'
runs-on: ubuntu-latest
+ permissions:
+ pull-requests: read
timeout-minutes: 10
steps:
- - uses: mheap/github-action-required-labels@v5
+ - uses: mheap/github-action-required-labels@0ac283b4e65c1fb28ce6079dea5546ceca98ccbe # v5.5.2
with:
mode: exactly
count: 0
diff --git a/.github/workflows/reusable-check-c-api-docs.yml b/.github/workflows/reusable-check-c-api-docs.yml
new file mode 100644
index 000000000000000..db030c80008b1ed
--- /dev/null
+++ b/.github/workflows/reusable-check-c-api-docs.yml
@@ -0,0 +1,25 @@
+name: Reusable C API Docs Check
+
+on:
+ workflow_call:
+
+permissions:
+ contents: read
+
+env:
+ FORCE_COLOR: 1
+
+jobs:
+ check-c-api-docs:
+ name: 'Check if all C APIs are documented'
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ steps:
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ with:
+ persist-credentials: false
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ with:
+ python-version: '3.x'
+ - name: Check for undocumented C APIs
+ run: python Tools/check-c-api-docs/main.py
diff --git a/.github/workflows/reusable-cifuzz.yml b/.github/workflows/reusable-cifuzz.yml
new file mode 100644
index 000000000000000..9b49e7fd26f0078
--- /dev/null
+++ b/.github/workflows/reusable-cifuzz.yml
@@ -0,0 +1,49 @@
+# CIFuzz job based on https://google.github.io/oss-fuzz/getting-started/continuous-integration/
+name: Reusable CIFuzz
+
+on:
+ workflow_call:
+ inputs:
+ oss-fuzz-project-name:
+ description: OSS-Fuzz project name
+ required: true
+ type: string
+ sanitizer:
+ description: OSS-Fuzz sanitizer
+ required: true
+ type: string
+
+permissions:
+ contents: read
+
+jobs:
+ cifuzz:
+ name: ${{ inputs.oss-fuzz-project-name }} (${{ inputs.sanitizer }})
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+ steps:
+ - name: Build fuzzers (${{ inputs.sanitizer }})
+ id: build
+ uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@ed23f8af80ff82b25ca67cd9b101e690b8897b3f # master
+ with:
+ oss-fuzz-project-name: ${{ inputs.oss-fuzz-project-name }}
+ sanitizer: ${{ inputs.sanitizer }}
+ - name: Run fuzzers (${{ inputs.sanitizer }})
+ uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@ed23f8af80ff82b25ca67cd9b101e690b8897b3f # master
+ with:
+ fuzz-seconds: 600
+ oss-fuzz-project-name: ${{ inputs.oss-fuzz-project-name }}
+ output-sarif: true
+ sanitizer: ${{ inputs.sanitizer }}
+ - name: Upload crash
+ if: failure() && steps.build.outcome == 'success'
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
+ with:
+ name: ${{ inputs.sanitizer }}-artifacts
+ path: ./out/artifacts
+ - name: Upload SARIF
+ if: always() && steps.build.outcome == 'success'
+ uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
+ with:
+ sarif_file: cifuzz-sarif/results.sarif
+ checkout_path: cifuzz-sarif
diff --git a/.github/workflows/reusable-context.yml b/.github/workflows/reusable-context.yml
new file mode 100644
index 000000000000000..8ed6873104db7be
--- /dev/null
+++ b/.github/workflows/reusable-context.yml
@@ -0,0 +1,121 @@
+name: Reusable build context
+
+on: # yamllint disable-line rule:truthy
+ workflow_call:
+ outputs:
+ # Every referenced step MUST always set its output variable,
+ # either via ``Tools/build/compute-changes.py`` or in this workflow file.
+ # Boolean outputs (generally prefixed ``run-``) can then later be used
+ # safely through the following idiom in job conditionals and other
+ # expressions. Here's some examples:
+ #
+ # if: fromJSON(needs.build-context.outputs.run-tests)
+ #
+ # ${{
+ # fromJSON(needs.build-context.outputs.run-tests)
+ # && 'truthy-branch'
+ # || '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 for 'cpython' fuzzer
+ value: ${{ jobs.compute-changes.outputs.run-ci-fuzz }} # bool
+ run-ci-fuzz-stdlib:
+ description: Whether to run the CIFuzz job for 'python3-libraries' fuzzer
+ value: ${{ jobs.compute-changes.outputs.run-ci-fuzz-stdlib }} # bool
+ run-docs:
+ description: Whether to build the docs
+ value: ${{ jobs.compute-changes.outputs.run-docs }} # 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
+
+permissions:
+ contents: read
+
+jobs:
+ compute-changes:
+ name: Create context from changed files
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ outputs:
+ run-android: ${{ steps.changes.outputs.run-android }}
+ run-ci-fuzz: ${{ steps.changes.outputs.run-ci-fuzz }}
+ run-ci-fuzz-stdlib: ${{ steps.changes.outputs.run-ci-fuzz-stdlib }}
+ run-docs: ${{ steps.changes.outputs.run-docs }}
+ 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:
+ - name: Set up Python
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ with:
+ python-version: "3"
+
+ - run: >-
+ echo '${{ github.event_name }}'
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ ref: >-
+ ${{
+ github.event_name == 'pull_request'
+ && github.event.pull_request.head.sha
+ || ''
+ }}
+
+ # Adapted from https://github.com/actions/checkout/issues/520#issuecomment-1167205721
+ - name: Fetch commits to get branch diff
+ if: github.event_name == 'pull_request'
+ run: |
+ set -eux
+
+ # Fetch enough history to find a common ancestor commit (aka merge-base):
+ git fetch origin "${refspec_pr}" --depth=$(( commits + 1 )) \
+ --no-tags --prune --no-recurse-submodules
+
+ # This should get the oldest commit in the local fetched history (which may not be the commit the PR branched from):
+ COMMON_ANCESTOR=$( git rev-list --first-parent --max-parents=0 --max-count=1 "${branch_pr}" )
+ DATE=$( git log --date=iso8601 --format=%cd "${COMMON_ANCESTOR}" )
+
+ # Get all commits since that commit date from the base branch (eg: main):
+ git fetch origin "${refspec_base}" --shallow-since="${DATE}" \
+ --no-tags --prune --no-recurse-submodules
+ env:
+ branch_pr: 'origin/${{ github.event.pull_request.head.ref }}'
+ commits: ${{ github.event.pull_request.commits }}
+ refspec_base: '+${{ github.event.pull_request.base.sha }}:remotes/origin/${{ github.event.pull_request.base.ref }}'
+ refspec_pr: '+${{ github.event.pull_request.head.sha }}:remotes/origin/${{ github.event.pull_request.head.ref }}'
+
+ # We only want to run tests on PRs when related files are changed,
+ # or when someone triggers a manual workflow run.
+ - name: Compute changed files
+ id: changes
+ run: python Tools/build/compute-changes.py
+ env:
+ GITHUB_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
+ GITHUB_EVENT_NAME: ${{ github.event_name }}
+ CCF_TARGET_REF: ${{ github.base_ref || github.event.repository.default_branch }}
+ CCF_HEAD_REF: ${{ github.event.pull_request.head.sha || github.sha }}
diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml
index 9e26d7847d2bd33..6db7668aef9506e 100644
--- a/.github/workflows/reusable-docs.yml
+++ b/.github/workflows/reusable-docs.yml
@@ -1,8 +1,19 @@
-name: Docs
+name: Reusable Docs
on:
workflow_call:
workflow_dispatch:
+ # Pushes to CPython branches seed the pip caches under the exact keys every
+ # docs PR restores from. Without a branch-scoped copy, each PR saves a
+ # duplicate into its own refs/pull/N/merge scope that nothing else can read.
+ push:
+ branches:
+ - main
+ - '3.*'
+ paths:
+ - 'Doc/pylock.toml'
+ - 'Doc/requirements.txt'
+ - '.github/workflows/reusable-docs.yml'
permissions:
contents: read
@@ -11,37 +22,48 @@ concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
+env:
+ FORCE_COLOR: 1
+
jobs:
- build_doc:
+ build-doc:
name: 'Docs'
runs-on: ubuntu-latest
timeout-minutes: 60
env:
branch_base: 'origin/${{ github.event.pull_request.base.ref }}'
branch_pr: 'origin/${{ github.event.pull_request.head.ref }}'
+ commits: ${{ github.event.pull_request.commits }}
refspec_base: '+${{ github.event.pull_request.base.sha }}:remotes/origin/${{ github.event.pull_request.base.ref }}'
refspec_pr: '+${{ github.event.pull_request.head.sha }}:remotes/origin/${{ github.event.pull_request.head.ref }}'
steps:
- name: 'Check out latest PR branch commit'
- uses: actions/checkout@v4
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
- ref: ${{ github.event.pull_request.head.sha }}
+ persist-credentials: false
+ ref: >-
+ ${{
+ github.event_name == 'pull_request'
+ && github.event.pull_request.head.sha
+ || ''
+ }}
# Adapted from https://github.com/actions/checkout/issues/520#issuecomment-1167205721
- name: 'Fetch commits to get branch diff'
+ if: github.event_name == 'pull_request'
run: |
# Fetch enough history to find a common ancestor commit (aka merge-base):
- git fetch origin ${{ env.refspec_pr }} --depth=$(( ${{ github.event.pull_request.commits }} + 1 )) \
+ git fetch origin "${refspec_pr}" --depth=$(( commits + 1 )) \
--no-tags --prune --no-recurse-submodules
# This should get the oldest commit in the local fetched history (which may not be the commit the PR branched from):
- COMMON_ANCESTOR=$( git rev-list --first-parent --max-parents=0 --max-count=1 ${{ env.branch_pr }} )
+ COMMON_ANCESTOR=$( git rev-list --first-parent --max-parents=0 --max-count=1 "${branch_pr}" )
DATE=$( git log --date=iso8601 --format=%cd "${COMMON_ANCESTOR}" )
# Get all commits since that commit date from the base branch (eg: master or main):
- git fetch origin ${{ env.refspec_base }} --shallow-since="${DATE}" \
+ git fetch origin "${refspec_base}" --shallow-since="${DATE}" \
--no-tags --prune --no-recurse-submodules
- name: 'Set up Python'
- uses: actions/setup-python@v5
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3'
cache: 'pip'
@@ -54,49 +76,37 @@ jobs:
continue-on-error: true
run: |
set -Eeuo pipefail
- # Build docs with the '-n' (nit-picky) option; write warnings to file
- make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n -W --keep-going -w sphinx-warnings.txt" html
+ # Build docs with the nit-picky option; write warnings to file
+ make -C Doc/ PYTHON=../python SPHINXOPTS="--quiet --nitpicky --warning-file sphinx-warnings.txt" html
- name: 'Check warnings'
if: github.event_name == 'pull_request'
run: |
python Doc/tools/check-warnings.py \
- --annotate-diff '${{ env.branch_base }}' '${{ env.branch_pr }}' \
+ --annotate-diff "${branch_base}" "${branch_pr}" \
--fail-if-regression \
- --fail-if-improved
-
- # This build doesn't use problem matchers or check annotations
- build_doc_oldest_supported_sphinx:
- name: 'Docs (Oldest Sphinx)'
- runs-on: ubuntu-latest
- timeout-minutes: 60
- steps:
- - uses: actions/checkout@v4
- - name: 'Set up Python'
- uses: actions/setup-python@v5
- with:
- python-version: '3.12' # known to work with Sphinx 6.2.1
- cache: 'pip'
- cache-dependency-path: 'Doc/requirements-oldest-sphinx.txt'
- - name: 'Install build dependencies'
- run: make -C Doc/ venv REQUIREMENTS="requirements-oldest-sphinx.txt"
- - name: 'Build HTML documentation'
- run: make -C Doc/ SPHINXOPTS="-q" SPHINXERRORHANDLING="-W --keep-going" html
+ --fail-if-improved \
+ --fail-if-new-news-nit
+ - name: 'Build list of changes'
+ run: |
+ make -C Doc/ PYTHON=../python changes
# Run "doctest" on HEAD as new syntax doesn't exist in the latest stable release
doctest:
name: 'Doctest'
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- - uses: actions/checkout@v4
- - uses: actions/cache@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: ~/.cache/pip
key: ubuntu-doc-${{ hashFiles('Doc/requirements.txt') }}
restore-keys: |
ubuntu-doc-
- name: 'Install Dependencies'
- run: sudo ./.github/workflows/posix-deps-apt.sh && sudo apt-get install wamerican
+ run: sudo ./.github/workflows/posix-deps-apt.sh && sudo apt-get install --no-install-recommends wamerican
- name: 'Configure CPython'
run: ./configure --with-pydebug
- name: 'Build CPython'
@@ -105,4 +115,31 @@ jobs:
run: make -C Doc/ PYTHON=../python venv
# Use "xvfb-run" since some doctest tests open GUI windows
- name: 'Run documentation doctest'
- run: xvfb-run make -C Doc/ PYTHON=../python SPHINXERRORHANDLING="-W --keep-going" doctest
+ run: xvfb-run make -C Doc/ PYTHON=../python SPHINXERRORHANDLING="--fail-on-warning" doctest
+
+ check-epub:
+ name: 'Check EPUB'
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - name: 'Set up Python'
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
+ with:
+ python-version: '3'
+ cache: 'pip'
+ cache-dependency-path: 'Doc/requirements.txt'
+ - name: 'Install build dependencies'
+ run: |
+ make -C Doc/ venv
+ python -m pip install epubcheck
+ - name: 'Build EPUB documentation'
+ run: make -C Doc/ PYTHON=../python epub
+ - name: 'Run epubcheck'
+ continue-on-error: true
+ run: epubcheck Doc/build/epub/Python.epub &> Doc/epubcheck.txt
+ - run: cat Doc/epubcheck.txt
+ - name: 'Check for fatal errors in EPUB'
+ run: python Doc/tools/check-epub.py
diff --git a/.github/workflows/reusable-install.yml b/.github/workflows/reusable-install.yml
new file mode 100644
index 000000000000000..79b7147b12c368f
--- /dev/null
+++ b/.github/workflows/reusable-install.yml
@@ -0,0 +1,44 @@
+name: Reusable Ubuntu (installed)
+
+on:
+ workflow_call:
+
+permissions:
+ contents: read
+
+env:
+ FORCE_COLOR: 1
+
+jobs:
+ build-install-test:
+ name: build, install and test
+ runs-on: ubuntu-24.04-arm
+ timeout-minutes: 60
+ env:
+ PYTHONSTRICTEXTENSIONBUILD: 1
+ steps:
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+ with:
+ persist-credentials: false
+ - name: Register gcc problem matcher
+ run: echo "::add-matcher::.github/problem-matchers/gcc.json"
+ - name: Set install dir
+ run:
+ echo "INSTALL_DIR=$(realpath "${GITHUB_WORKSPACE}/../installed-python")" >> "$GITHUB_ENV"
+ - name: Install dependencies
+ run: sudo ./.github/workflows/posix-deps-apt.sh
+ - name: Configure CPython
+ run: ./configure --config-cache --prefix="$INSTALL_DIR"
+ - name: Build CPython
+ run: make -j
+ - name: Install CPython
+ run: make install
+ - name: Set installed interpreter
+ run: |
+ ldversion=$(./python -c 'import sysconfig; print(sysconfig.get_config_var("LDVERSION"))')
+ echo "INSTALLED_PYTHON=${INSTALL_DIR}/bin/python${ldversion}" >> "$GITHUB_ENV"
+ - name: Display build info
+ run: |
+ "$INSTALLED_PYTHON" -m test.pythoninfo
+ - name: Test the installed Python
+ run: xvfb-run "$INSTALLED_PYTHON" -m test --fast-ci --timeout=900
diff --git a/.github/workflows/reusable-macos.yml b/.github/workflows/reusable-macos.yml
index d06a718d199c96d..04f4d03b49129a2 100644
--- a/.github/workflows/reusable-macos.yml
+++ b/.github/workflows/reusable-macos.yml
@@ -1,20 +1,27 @@
+name: Reusable macOS
+
on:
workflow_call:
inputs:
- config_hash:
- required: true
- type: string
free-threading:
required: false
type: boolean
default: false
- os-matrix:
- required: false
+ os:
+ description: OS to run the job
+ required: true
type: string
+permissions:
+ contents: read
+
+env:
+ FORCE_COLOR: 1
+
jobs:
- build_macos:
- name: 'build and test'
+ build-macos:
+ name: build and test (${{ inputs.os }})
+ runs-on: ${{ inputs.os }}
timeout-minutes: 60
env:
HOMEBREW_NO_ANALYTICS: 1
@@ -23,22 +30,17 @@ jobs:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
PYTHONSTRICTEXTENSIONBUILD: 1
TERM: linux
- strategy:
- fail-fast: false
- matrix:
- os: ${{fromJson(inputs.os-matrix)}}
- runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v4
- - name: Runner image version
- run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
- - name: Restore config.cache
- uses: actions/cache@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
- path: config.cache
- key: ${{ github.job }}-${{ matrix.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}
+ persist-credentials: false
+ - name: Runner image version
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Install Homebrew dependencies
- run: brew install pkg-config openssl@3.0 xz gdbm tcl-tk
+ run: |
+ brew bundle --file=Misc/Brewfile
+ # Because alternate versions are not symlinked into place by default:
+ brew link --overwrite tcl-tk@8
- name: Configure CPython
run: |
GDBM_CFLAGS="-I$(brew --prefix gdbm)/include" \
diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml
new file mode 100644
index 000000000000000..f4b23eed8bff573
--- /dev/null
+++ b/.github/workflows/reusable-san.yml
@@ -0,0 +1,104 @@
+name: Reusable Sanitizer
+
+on:
+ workflow_call:
+ inputs:
+ sanitizer:
+ required: true
+ type: string
+ free-threading:
+ description: Whether to use free-threaded mode
+ required: false
+ type: boolean
+ default: false
+
+permissions:
+ contents: read
+
+env:
+ FORCE_COLOR: 1
+
+jobs:
+ build-san-reusable:
+ name: >-
+ ${{ inputs.sanitizer }}${{
+ inputs.free-threading
+ && ' (free-threading)'
+ || ''
+ }}
+ runs-on: ubuntu-24.04
+ timeout-minutes: 60
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - name: Runner image version
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
+ - name: Install dependencies
+ run: |
+ sudo ./.github/workflows/posix-deps-apt.sh
+ # Install clang
+ wget https://apt.llvm.org/llvm.sh
+ chmod +x llvm.sh
+ sudo ./llvm.sh 20
+ sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-20 100
+ sudo update-alternatives --set clang /usr/bin/clang-20
+ sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-20 100
+ sudo update-alternatives --set clang++ /usr/bin/clang++-20
+
+ if [ "${SANITIZER}" = "TSan" ]; then
+ # Reduce ASLR to avoid TSan crashing
+ sudo sysctl -w vm.mmap_rnd_bits=28
+ fi
+
+ - name: Sanitizer option setup
+ run: |
+ if [ "${SANITIZER}" = "TSan" ]; then
+ echo "TSAN_OPTIONS=${SAN_LOG_OPTION} suppressions=${GITHUB_WORKSPACE}/Tools/tsan/suppressions${{
+ inputs.free-threading
+ && '_free_threading'
+ || ''
+ }}.txt handle_segv=0" >> "$GITHUB_ENV"
+ else
+ echo "UBSAN_OPTIONS=${SAN_LOG_OPTION}" >> "$GITHUB_ENV"
+ fi
+ echo "CC=clang" >> "$GITHUB_ENV"
+ echo "CXX=clang++" >> "$GITHUB_ENV"
+ env:
+ SANITIZER: ${{ inputs.sanitizer }}
+ SAN_LOG_OPTION: log_path=${{ github.workspace }}/san_log
+ - name: Configure CPython
+ run: >-
+ ./configure
+ --config-cache
+ ${{
+ inputs.sanitizer == 'TSan'
+ && '--with-thread-sanitizer'
+ || '--with-undefined-behavior-sanitizer'
+ }}
+ --with-pydebug
+ ${{ inputs.free-threading && '--disable-gil' || '' }}
+ - name: Build CPython
+ run: make -j4
+ - name: Display build info
+ run: make pythoninfo
+ - name: Tests
+ run: >-
+ ./python -m test
+ ${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }}
+ -j4 -W
+ - name: Display logs
+ if: always()
+ run: find "${GITHUB_WORKSPACE}" -name 'san_log.*' | xargs head -n 1000
+ - name: Archive logs
+ if: always()
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
+ with:
+ name: >-
+ ${{ inputs.sanitizer }}-logs-${{
+ inputs.free-threading
+ && 'free-threading'
+ || 'default'
+ }}
+ path: san_log.*
+ if-no-files-found: ignore
diff --git a/.github/workflows/reusable-tsan.yml b/.github/workflows/reusable-tsan.yml
deleted file mode 100644
index 48bd5b547e8cba8..000000000000000
--- a/.github/workflows/reusable-tsan.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-on:
- workflow_call:
- inputs:
- config_hash:
- required: true
- type: string
- options:
- required: true
- type: string
- suppressions_path:
- description: 'A repo relative path to the suppressions file'
- required: true
- type: string
-
-jobs:
- build_tsan_reusable:
- name: 'Thread sanitizer'
- runs-on: ubuntu-22.04
- timeout-minutes: 60
- steps:
- - uses: actions/checkout@v4
- - name: Runner image version
- run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
- - name: Restore config.cache
- uses: actions/cache@v4
- with:
- path: config.cache
- key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}
- - name: Install Dependencies
- run: |
- sudo ./.github/workflows/posix-deps-apt.sh
- # Install clang-18
- wget https://apt.llvm.org/llvm.sh
- chmod +x llvm.sh
- sudo ./llvm.sh 18
- sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 100
- sudo update-alternatives --set clang /usr/bin/clang-18
- sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 100
- sudo update-alternatives --set clang++ /usr/bin/clang++-18
- # Reduce ASLR to avoid TSAN crashing
- sudo sysctl -w vm.mmap_rnd_bits=28
- - name: TSAN Option Setup
- run: |
- echo "TSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/${{ inputs.suppressions_path }}" >> $GITHUB_ENV
- echo "CC=clang" >> $GITHUB_ENV
- echo "CXX=clang++" >> $GITHUB_ENV
- - 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: ${{ inputs.options }}
- - name: Build CPython
- run: make -j4
- - name: Display build info
- run: make pythoninfo
- - name: Tests
- run: ./python -m test --tsan -j4
diff --git a/.github/workflows/reusable-ubuntu.yml b/.github/workflows/reusable-ubuntu.yml
index fa450ed33763219..d8f65795d0bc801 100644
--- a/.github/workflows/reusable-ubuntu.yml
+++ b/.github/workflows/reusable-ubuntu.yml
@@ -1,78 +1,82 @@
+name: Reusable Ubuntu
+
on:
workflow_call:
inputs:
- config_hash:
- required: true
- type: string
- options:
- required: true
- type: string
+ free-threading:
+ description: Whether to use free-threaded mode
+ required: false
+ type: boolean
+ default: false
+
+permissions:
+ contents: read
+
+env:
+ FORCE_COLOR: 1
jobs:
- build_ubuntu_reusable:
+ build-ubuntu-reusable:
name: 'build and test'
+ runs-on: ${{ matrix.os }}
timeout-minutes: 60
- runs-on: ubuntu-22.04
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-24.04, ubuntu-24.04-arm]
env:
- FORCE_COLOR: 1
- OPENSSL_VER: 3.0.13
+ OPENSSL_VER: 3.0.22
PYTHONSTRICTEXTENSIONBUILD: 1
TERM: linux
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
- name: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- name: Install dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: Configure OpenSSL env vars
run: |
- echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV
- echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV
- echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV
+ echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV"
+ echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV"
+ echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
- name: 'Restore OpenSSL build'
id: cache-openssl
- uses: actions/cache@v4
+ uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
- key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
+ key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
- name: Install OpenSSL
if: steps.cache-openssl.outputs.cache-hit != 'true'
- run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux
- - name: Add ccache to PATH
- run: |
- echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
- - name: Configure ccache action
- uses: hendrikmuhs/ccache-action@v1.2
- with:
- save: ${{ github.event_name == 'push' }}
- max-size: "200M"
+ run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux
- name: Setup directory envs for out-of-tree builds
run: |
- echo "CPYTHON_RO_SRCDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-ro-srcdir)" >> $GITHUB_ENV
- echo "CPYTHON_BUILDDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-builddir)" >> $GITHUB_ENV
+ echo "CPYTHON_RO_SRCDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-ro-srcdir)" >> "$GITHUB_ENV"
+ echo "CPYTHON_BUILDDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-builddir)" >> "$GITHUB_ENV"
- name: Create directories for read-only out-of-tree builds
- run: mkdir -p $CPYTHON_RO_SRCDIR $CPYTHON_BUILDDIR
+ run: mkdir -p "$CPYTHON_RO_SRCDIR" "$CPYTHON_BUILDDIR"
- name: Bind mount sources read-only
- run: sudo mount --bind -o ro $GITHUB_WORKSPACE $CPYTHON_RO_SRCDIR
+ run: sudo mount --bind -o ro "$GITHUB_WORKSPACE" "$CPYTHON_RO_SRCDIR"
- name: Runner image version
- run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
- - name: Restore config.cache
- uses: actions/cache@v4
- with:
- path: ${{ env.CPYTHON_BUILDDIR }}/config.cache
- key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Configure CPython out-of-tree
working-directory: ${{ env.CPYTHON_BUILDDIR }}
- run: ${{ inputs.options }}
+ run: >-
+ ../cpython-ro-srcdir/configure
+ --config-cache
+ --with-pydebug
+ --with-openssl="$OPENSSL_DIR"
+ ${{ inputs.free-threading && '--disable-gil' || '' }}
- name: Build CPython out-of-tree
working-directory: ${{ env.CPYTHON_BUILDDIR }}
- run: make -j4
+ run: make -j
- name: Display build info
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: make pythoninfo
- name: Remount sources writable for tests
# some tests write to srcdir, lack of pyc files slows down testing
- run: sudo mount $CPYTHON_RO_SRCDIR -oremount,rw
+ run: sudo mount "$CPYTHON_RO_SRCDIR" -oremount,rw
- name: Tests
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: xvfb-run make test
diff --git a/.github/workflows/reusable-wasi.yml b/.github/workflows/reusable-wasi.yml
index c389fe9e173b38d..41fad6d72dbf2c7 100644
--- a/.github/workflows/reusable-wasi.yml
+++ b/.github/workflows/reusable-wasi.yml
@@ -1,73 +1,63 @@
+name: Reusable WASI
+
on:
workflow_call:
- inputs:
- config_hash:
- required: true
- type: string
+
+permissions:
+ contents: read
+
+env:
+ FORCE_COLOR: 1
jobs:
- build_wasi_reusable:
+ build-wasi-reusable:
name: 'build and test'
+ runs-on: ubuntu-24.04
timeout-minutes: 60
- runs-on: ubuntu-22.04
env:
- WASMTIME_VERSION: 18.0.3
- WASI_SDK_VERSION: 21
+ WASMTIME_VERSION: 38.0.3
+ WASI_SDK_VERSION: 24
WASI_SDK_PATH: /opt/wasi-sdk
- CROSS_BUILD_PYTHON: cross-build/build
- CROSS_BUILD_WASI: cross-build/wasm32-wasi
+ CROSS_BUILD_WASI: cross-build/wasm32-wasip1
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
# No problem resolver registered as one doesn't currently exist for Clang.
- name: "Install wasmtime"
- uses: jcbhmr/setup-wasmtime@v2
+ uses: bytecodealliance/actions/wasmtime/setup@9152e710e9f7182e4c29ad218e4f335a7b203613 # v1.1.3
with:
- wasmtime-version: ${{ env.WASMTIME_VERSION }}
+ version: ${{ env.WASMTIME_VERSION }}
- name: "Restore WASI SDK"
id: cache-wasi-sdk
- uses: actions/cache@v4
+ uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: ${{ env.WASI_SDK_PATH }}
key: ${{ runner.os }}-wasi-sdk-${{ env.WASI_SDK_VERSION }}
- - name: "Install WASI SDK"
+ - name: "Install WASI SDK" # Hard-coded to x64.
if: steps.cache-wasi-sdk.outputs.cache-hit != 'true'
run: |
- mkdir ${{ env.WASI_SDK_PATH }} && \
- curl -s -S --location https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${{ env.WASI_SDK_VERSION }}/wasi-sdk-${{ env.WASI_SDK_VERSION }}.0-linux.tar.gz | \
- tar --strip-components 1 --directory ${{ env.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
+ 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-x86_64-linux.tar.gz" | \
+ tar --strip-components 1 --directory "${WASI_SDK_PATH}" --extract --gunzip
- name: "Install Python"
- uses: actions/setup-python@v5
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.x'
- - 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
- key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}-${{ env.pythonLocation }}
+ - name: "Runner image version"
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: "Configure build Python"
run: python3 Tools/wasm/wasi.py configure-build-python -- --config-cache --with-pydebug
- name: "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
- # Include env.pythonLocation in key to avoid changes in environment when setup-python updates Python
- key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-wasi-sdk-${{ env.WASI_SDK_VERSION }}-${{ inputs.config_hash }}-${{ env.pythonLocation }}
- - name: "Configure host"
+ - name: "Display build info of the build Python"
+ run: python3 Tools/wasm/wasi.py pythoninfo-build
+ - name: "Configure host/WASI Python"
# `--with-pydebug` inferred from configure-build-python
run: python3 Tools/wasm/wasi.py configure-host -- --config-cache
- - name: "Make host"
+ - name: "Make host/WASI Python"
run: python3 Tools/wasm/wasi.py make-host
- - name: "Display build info"
- run: make --directory ${{ env.CROSS_BUILD_WASI }} pythoninfo
+ - name: "Display build info of the host/WASI Python"
+ run: python3 Tools/wasm/wasi.py pythoninfo-host
- name: "Test"
- run: make --directory ${{ env.CROSS_BUILD_WASI }} test
+ run: make --directory "${CROSS_BUILD_WASI}" test
diff --git a/.github/workflows/reusable-windows-msi.yml b/.github/workflows/reusable-windows-msi.yml
new file mode 100644
index 000000000000000..e690224f35537b8
--- /dev/null
+++ b/.github/workflows/reusable-windows-msi.yml
@@ -0,0 +1,31 @@
+name: Reusable Windows MSI
+
+on:
+ workflow_call:
+ inputs:
+ arch:
+ description: CPU architecture
+ required: true
+ type: string
+
+permissions:
+ contents: read
+
+env:
+ FORCE_COLOR: 1
+
+jobs:
+ build:
+ name: installer for ${{ inputs.arch }}
+ runs-on: windows-2022
+ timeout-minutes: 60
+ env:
+ ARCH: ${{ inputs.arch }}
+ IncludeFreethreaded: true
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - name: Build CPython installer
+ run: ./Tools/msi/build.bat --doc -"${ARCH}"
+ shell: bash
diff --git a/.github/workflows/reusable-windows.yml b/.github/workflows/reusable-windows.yml
index c0209e0e1c92e93..74ee4513fb6b1c5 100644
--- a/.github/workflows/reusable-windows.yml
+++ b/.github/workflows/reusable-windows.yml
@@ -1,53 +1,59 @@
+name: Reusable Windows
+
on:
workflow_call:
inputs:
+ os:
+ description: OS to run on
+ required: true
+ type: string
+ arch:
+ description: CPU architecture
+ required: true
+ type: string
free-threading:
+ description: Whether to compile CPython in free-threading mode
required: false
type: boolean
default: false
-jobs:
- build_win32:
- name: 'build and test (x86)'
- runs-on: windows-latest
- timeout-minutes: 60
- env:
- IncludeUwp: 'true'
- steps:
- - uses: actions/checkout@v4
- - name: Build CPython
- run: .\PCbuild\build.bat -e -d -v -p Win32 ${{ inputs.free-threading && '--disable-gil' || '' }}
- - name: Display build info
- run: .\python.bat -m test.pythoninfo
- - name: Tests
- run: .\PCbuild\rt.bat -p Win32 -d -q --fast-ci ${{ inputs.free-threading && '--disable-gil' || '' }}
+permissions:
+ contents: read
- build_win_amd64:
- name: 'build and test (x64)'
- runs-on: windows-latest
- timeout-minutes: 60
- env:
- IncludeUwp: 'true'
- steps:
- - uses: actions/checkout@v4
- - name: Register MSVC problem matcher
- run: echo "::add-matcher::.github/problem-matchers/msvc.json"
- - name: Build CPython
- run: .\PCbuild\build.bat -e -d -v -p x64 ${{ inputs.free-threading && '--disable-gil' || '' }}
- - name: Display build info
- run: .\python.bat -m test.pythoninfo
- - name: Tests
- run: .\PCbuild\rt.bat -p x64 -d -q --fast-ci ${{ inputs.free-threading && '--disable-gil' || '' }}
+env:
+ FORCE_COLOR: 1
+ IncludeUwp: >-
+ true
- build_win_arm64:
- name: 'build (arm64)'
- runs-on: windows-latest
+jobs:
+ build:
+ name: ${{ inputs.arch == 'arm64' && 'build' || 'build and test' }} (${{ inputs.arch }})
+ runs-on: ${{ inputs.os }}
timeout-minutes: 60
env:
- IncludeUwp: 'true'
+ ARCH: ${{ inputs.arch }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
- name: Register MSVC problem matcher
+ if: inputs.arch != 'Win32'
run: echo "::add-matcher::.github/problem-matchers/msvc.json"
- name: Build CPython
- run: .\PCbuild\build.bat -e -d -v -p arm64 ${{ inputs.free-threading && '--disable-gil' || '' }}
+ run: >-
+ .\\PCbuild\\build.bat
+ -e -d -v
+ -p "${ARCH}"
+ ${{ inputs.free-threading && '--disable-gil' || '' }}
+ shell: bash
+ - name: Display build info # FIXME(diegorusso): remove the `if`
+ if: inputs.arch != 'arm64'
+ run: .\\python.bat -m test.pythoninfo
+ - name: Tests # FIXME(diegorusso): remove the `if`
+ if: inputs.arch != 'arm64'
+ run: >-
+ .\\PCbuild\\rt.bat
+ -p "${ARCH}"
+ -d -q --fast-ci
+ ${{ inputs.free-threading && '--disable-gil' || '' }}
+ shell: bash
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index f97587e68cbbe43..1fbc4a20dbc7ddd 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -5,18 +5,19 @@ on:
- cron: "0 */6 * * *"
permissions:
- pull-requests: write
+ contents: read
jobs:
stale:
if: github.repository_owner == 'python'
-
runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
timeout-minutes: 10
steps:
- name: "Check PRs"
- uses: actions/stale@v9
+ uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity.'
diff --git a/.github/workflows/verify-ensurepip-wheels.yml b/.github/workflows/verify-ensurepip-wheels.yml
index 83b007f1c9c2efe..cb40f6abc0b3b75 100644
--- a/.github/workflows/verify-ensurepip-wheels.yml
+++ b/.github/workflows/verify-ensurepip-wheels.yml
@@ -25,8 +25,10 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-python@v5
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3'
- name: Compare checksum of bundled wheels to the ones published on PyPI
diff --git a/.github/workflows/verify-expat.yml b/.github/workflows/verify-expat.yml
new file mode 100644
index 000000000000000..472a11db2da5fbf
--- /dev/null
+++ b/.github/workflows/verify-expat.yml
@@ -0,0 +1,32 @@
+name: Verify bundled libexpat
+
+on:
+ workflow_dispatch:
+ push:
+ paths:
+ - 'Modules/expat/**'
+ - '.github/workflows/verify-expat.yml'
+ pull_request:
+ paths:
+ - 'Modules/expat/**'
+ - '.github/workflows/verify-expat.yml'
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
+ cancel-in-progress: true
+
+jobs:
+ verify:
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - name: Download and verify bundled libexpat files
+ run: |
+ ./Modules/expat/refresh.sh
+ git diff --exit-code Modules/expat/
diff --git a/.github/zizmor.yml b/.github/zizmor.yml
new file mode 100644
index 000000000000000..7c776d5ea1f941a
--- /dev/null
+++ b/.github/zizmor.yml
@@ -0,0 +1,6 @@
+# Configuration for the zizmor static analysis tool, run via prek in CI
+# https://docs.zizmor.sh/configuration/
+rules:
+ dangerous-triggers:
+ ignore:
+ - documentation-links.yml
diff --git a/.gitignore b/.gitignore
index 8872e9d5508ff14..661f7c8ec4b4a61 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@ tags
TAGS
.vs/
.vscode/
+.cache/
gmon.out
.coverage
.mypy_cache/
@@ -79,7 +80,6 @@ iOS/testbed/Python.xcframework/ios-*/lib
iOS/testbed/Python.xcframework/ios-*/Python.framework
iOS/testbed/iOSTestbed.xcodeproj/project.xcworkspace
iOS/testbed/iOSTestbed.xcodeproj/xcuserdata
-iOS/testbed/iOSTestbed.xcodeproj/xcshareddata
Mac/Makefile
Mac/PythonLauncher/Info.plist
Mac/PythonLauncher/Makefile
@@ -134,14 +134,15 @@ Tools/unicode/data/
/config.log
/config.status
/config.status.lineno
-# hendrikmuhs/ccache-action@v1
/.ccache
/cross-build/
-/jit_stencils.h
+/jit_stencils*.h
+/jit_unwind_info*.h
/platform
/profile-clean-stamp
/profile-run-stamp
/profile-bolt-stamp
+/profile-gen-stamp
/pybuilddir.txt
/pyconfig.h
/python-config
@@ -169,5 +170,3 @@ Python/frozen_modules/MANIFEST
/python
!/Python/
-# main branch only: ABI files are not checked/maintained.
-Doc/data/python*.abi
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index fde9d9149bf62b1..7f8383e6b4aa75c 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,26 +1,72 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.3.4
+ rev: a27a2e47c7751b639d2b5badf0ef6ff11fee893f # frozen: v0.15.4
hooks:
- - id: ruff
- name: Run Ruff on Lib/test/
+ - id: ruff-check
+ name: Run Ruff (lint) on Doc/
+ args: [--exit-non-zero-on-fix]
+ files: ^Doc/
+ - id: ruff-check
+ name: Run Ruff (lint) on Lib/test/
args: [--exit-non-zero-on-fix]
files: ^Lib/test/
- - id: ruff
- name: Run Ruff on Argument Clinic
+ - id: ruff-check
+ name: Run Ruff (lint) on Tools/i18n/
+ args: [--exit-non-zero-on-fix, --config=Tools/i18n/.ruff.toml]
+ files: ^Tools/i18n/
+ - id: ruff-check
+ name: Run Ruff (lint) on Argument Clinic
args: [--exit-non-zero-on-fix, --config=Tools/clinic/.ruff.toml]
files: ^Tools/clinic/|Lib/test/test_clinic.py
+ - id: ruff-check
+ name: Run Ruff (lint) on Tools/peg_generator/
+ args: [--exit-non-zero-on-fix, --config=Tools/peg_generator/.ruff.toml]
+ files: ^Tools/peg_generator/
+ - id: ruff-check
+ 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 Doc/
+ args: [--exit-non-zero-on-fix]
+ files: ^Doc/
+ - id: ruff-format
+ name: Run Ruff (format) on Tools/wasm/
+ args: [--exit-non-zero-on-fix, --config=Tools/wasm/.ruff.toml]
+ files: ^Tools/wasm/
- repo: https://github.com/psf/black-pre-commit-mirror
- rev: 24.4.2
+ rev: ea488cebbfd88a5f50b8bd95d5c829d0bb76feb8 # frozen: 26.1.0
hooks:
- id: black
name: Run Black on Tools/jit/
files: ^Tools/jit/
- language_version: python3.12
+
+ - repo: https://github.com/Lucas-C/pre-commit-hooks
+ rev: ad1b27d73581aa16cca06fc4a0761fc563ffe8e8 # frozen: v1.5.6
+ hooks:
+ - id: remove-tabs
+ types: [python]
+ exclude: ^Tools/c-analyzer/cpython/_parser.py
+
+ - repo: local
+ hooks:
+ - id: blurb-no-space-c-api
+ name: Check C API news entries
+ language: fail
+ entry: Space found in path, move to Misc/NEWS.d/next/C_API/
+ files: Misc/NEWS.d/next/C API/20.*.rst
+
+ - repo: local
+ hooks:
+ - id: blurb-no-space-core-and-builtins
+ name: Check Core and Builtins news entries
+ language: fail
+ entry: Space found in path, move to Misc/NEWS.d/next/Core_and_Builtins/
+ files: Misc/NEWS.d/next/Core and Builtins/20.*.rst
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.5.0
+ rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0
hooks:
- id: check-case-conflict
- id: check-merge-conflict
@@ -28,13 +74,37 @@ repos:
exclude: ^Lib/test/test_tomllib/
- id: check-yaml
- id: end-of-file-fixer
- types: [python]
+ types_or: [python, yaml]
exclude: Lib/test/tokenizedata/coding20731.py
+ - id: end-of-file-fixer
+ files: '^\.github/CODEOWNERS$'
+ - id: mixed-line-ending
+ args: [--fix=auto]
+ exclude: '^Lib/test/.*data/'
+ - id: trailing-whitespace
+ types_or: [c, inc, python, rst, yaml]
- id: trailing-whitespace
- types_or: [c, inc, python, rst]
+ files: '^\.github/CODEOWNERS|\.(gram)$'
+
+ - repo: https://github.com/python-jsonschema/check-jsonschema
+ rev: 9f48a48aa91a6040d749ad68ec70907d907a5a7f # frozen: 0.37.0
+ hooks:
+ - id: check-dependabot
+ - id: check-github-workflows
+ - id: check-readthedocs
+
+ - repo: https://github.com/rhysd/actionlint
+ rev: 914e7df21a07ef503a81201c76d2b11c789d3fca # frozen: v1.7.12
+ hooks:
+ - id: actionlint
+
+ - repo: https://github.com/zizmorcore/zizmor-pre-commit
+ rev: b546b77c44c466a54a42af5499dcc0dcc1a3193f # frozen: v1.22.0
+ hooks:
+ - id: zizmor
- repo: https://github.com/sphinx-contrib/sphinx-lint
- rev: v0.9.1
+ rev: c883505f64b59c3c5c9375191e4ad9f98e727ccd # frozen: v1.0.2
hooks:
- id: sphinx-lint
args: [--enable=default-role]
diff --git a/.readthedocs.yml b/.readthedocs.yml
index 59830c79a404e0f..038417e4bb34385 100644
--- a/.readthedocs.yml
+++ b/.readthedocs.yml
@@ -8,25 +8,53 @@ sphinx:
configuration: Doc/conf.py
build:
- os: ubuntu-22.04
+ os: ubuntu-24.04
tools:
python: "3"
+ apt_packages:
+ - jq
- commands:
- # https://docs.readthedocs.io/en/stable/build-customization.html#cancel-build-based-on-a-condition
- #
- # Cancel building pull requests when there aren't changes in the Doc directory.
- #
- # If there are no changes (git diff exits with 0) we force the command to return with 183.
- # This is a special exit code on Read the Docs that will cancel the build immediately.
- - |
- if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && [ "$(git diff --quiet origin/main -- Doc/ .readthedocs.yml; echo $?)" -eq 0 ];
- then
- echo "No changes to Doc/ - exiting the build.";
- exit 183;
- fi
-
- - make -C Doc venv html
- - mkdir _readthedocs
- - mv Doc/build/html _readthedocs/html
-
+ jobs:
+ post_system_dependencies:
+ # https://docs.readthedocs.com/platform/stable/guides/build/skip-build.html#skip-builds-based-on-conditions
+ #
+ # Cancel building pull requests when there are no changes in the Doc
+ # directory or RTD configuration, or if we can't cleanly merge the base
+ # branch.
+ - |
+ set -eEux;
+ if [ "$READTHEDOCS_VERSION_TYPE" = "external" ];
+ then
+ base_branch=$(wget -qO- "https://api.github.com/repos/python/cpython/pulls/$READTHEDOCS_VERSION" | jq -er ".base.ref");
+ git fetch --depth=50 origin $base_branch:origin-$base_branch;
+ for attempt in $(seq 10);
+ do
+ if ! git merge-base HEAD origin-$base_branch;
+ then
+ git fetch --deepen=50 origin $base_branch;
+ else
+ break;
+ fi;
+ done;
+ if ! git -c "user.name=rtd" -c "user.email=no-reply@readthedocs.org" merge --no-stat --no-edit origin-$base_branch;
+ then
+ echo "Unsuccessful merge with '$base_branch' branch, skipping the build";
+ exit 183;
+ fi;
+ if git diff --exit-code --stat origin-$base_branch -- Doc/ .readthedocs.yml;
+ then
+ echo "No changes to Doc/ - skipping the build.";
+ exit 183;
+ fi;
+ fi;
+ create_environment:
+ - echo "Skipping default environment creation"
+ install:
+ - asdf plugin add uv
+ - asdf install uv latest
+ - asdf global uv latest
+ build:
+ html:
+ - make -C Doc venv html
+ - mkdir -p "$READTHEDOCS_OUTPUT"
+ - mv Doc/build/html "$READTHEDOCS_OUTPUT/"
diff --git a/.ruff.toml b/.ruff.toml
new file mode 100644
index 000000000000000..1c015fa88415bc9
--- /dev/null
+++ b/.ruff.toml
@@ -0,0 +1,12 @@
+# Default settings for Ruff in CPython
+
+# PYTHON_FOR_REGEN
+target-version = "py310"
+
+# PEP 8
+line-length = 79
+
+# Enable automatic fixes by default.
+# To override this, use ``fix = false`` in a subdirectory's config file
+# or ``--no-fix`` on the command line.
+fix = true
diff --git a/Android/README.md b/Android/README.md
index f5f463ca116589c..271ef94d0b40dfa 100644
--- a/Android/README.md
+++ b/Android/README.md
@@ -1,19 +1,22 @@
# Python for Android
-These instructions are only needed if you're planning to compile Python for
-Android yourself. Most users should *not* need to do this. If you're looking to
-use Python on Android, one of the following tools will provide a much more
-approachable user experience:
+If you obtained this README as part of a release package, then the only
+applicable sections are "Prerequisites", "Testing", and "Using in your own app".
-* [Briefcase](https://briefcase.readthedocs.io), from the BeeWare project
-* [Buildozer](https://buildozer.readthedocs.io), from the Kivy project
-* [Chaquopy](https://chaquo.com/chaquopy/)
+If you obtained this README as part of the CPython source tree, then you can
+also follow the other sections to compile Python for Android yourself.
+
+However, most app developers should not need to do any of these things manually.
+Instead, use one of the tools listed
+[here](https://docs.python.org/3/using/android.html), which will provide a much
+easier experience.
## Prerequisites
-Export the `ANDROID_HOME` environment variable to point at your Android SDK. If
-you don't already have the SDK, here's how to install it:
+If you already have an Android SDK installed, export the `ANDROID_HOME`
+environment variable to point at its location. Otherwise, here's how to install
+it:
* Download the "Command line tools" from .
* Create a directory `android-sdk/cmdline-tools`, and unzip the command line
@@ -22,25 +25,24 @@ you don't already have the SDK, here's how to install it:
`android-sdk/cmdline-tools/latest`.
* `export ANDROID_HOME=/path/to/android-sdk`
-The `android.py` script also requires the following commands to be on the `PATH`:
+The `android.py` script will automatically use the SDK's `sdkmanager` to install
+any packages it needs.
+
+The script also requires the following commands to be on the `PATH`:
* `curl`
-* `java`
-* `tar`
-* `unzip`
+* `java` (or set the `JAVA_HOME` environment variable).
+ Java versions 17, 21 and 25 are supported.
## Building
Python can be built for Android on any POSIX platform supported by the Android
-development tools, which currently means Linux or macOS. This involves doing a
-cross-build where you use a "build" Python (for your development machine) to
-help produce a "host" Python for Android.
+development tools, which currently means Linux or macOS.
-First, make sure you have all the usual tools and libraries needed to build
-Python for your development machine. The only Android tool you need to install
-is the command line tools package above: the build script will download the
-rest.
+First we'll make a "build" Python (for your development machine), then use it to
+help produce a "host" Python for Android. So make sure you have all the usual
+tools and libraries needed to build Python for your development machine.
The easiest way to do a build is to use the `android.py` script. You can either
have it perform the entire build process from start to finish in one step, or
@@ -65,8 +67,8 @@ To do all steps in a single command, run:
./android.py build HOST
```
-In the end you should have a build Python in `cross-build/build`, and an Android
-build in `cross-build/HOST`.
+In the end you should have a build Python in `cross-build/build`, and a host
+Python in `cross-build/HOST`.
You can use `--` as a separator for any of the `configure`-related commands –
including `build` itself – to pass arguments to the underlying `configure`
@@ -78,20 +80,82 @@ call. For example, if you want a pydebug build that also caches the results from
```
+## Packaging
+
+After building an architecture as described in the section above, you can
+package it for release with this command:
+
+```sh
+./android.py package HOST
+```
+
+`HOST` is defined in the section above.
+
+This will generate a tarball in `cross-build/HOST/dist`, whose structure is
+similar to the `Android` directory of the CPython source tree.
+
+
## Testing
-To run the Python test suite on Android:
-
-* Install Android Studio, if you don't already have it.
-* Follow the instructions in the previous section to build all supported
- architectures.
-* Run `./android.py setup-testbed` to download the Gradle wrapper.
-* Open the `testbed` directory in Android Studio.
-* In the *Device Manager* dock, connect a device or start an emulator.
- Then select it from the drop-down list in the toolbar.
-* Click the "Run" button in the toolbar.
-* The testbed app displays nothing on screen while running. To see its output,
- open the [Logcat window](https://developer.android.com/studio/debug/logcat).
-
-To run specific tests, or pass any other arguments to the test suite, edit the
-command line in testbed/app/src/main/python/main.py.
+The Python test suite can be run on Linux, macOS, or Windows.
+
+On Linux, the emulator needs access to the KVM virtualization interface. This may
+require adding your user to a group, or changing your udev rules. On GitHub
+Actions, the test script will do this automatically using the commands shown
+[here](https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/).
+
+You can run the test suite either:
+
+* Within the CPython repository, after doing a build as described above. On
+ Windows, you won't be able to do the build on the same machine, so you'll have
+ to copy the `cross-build/HOST/prefix` directory from somewhere else.
+
+* Or by taking a release package built using the `package` command, extracting
+ it wherever you want, and using its own copy of `android.py`.
+
+The test script supports the following modes:
+
+* In `--connected` mode, it runs on a device or emulator you have already
+ connected to the build machine. List the available devices with
+ `$ANDROID_HOME/platform-tools/adb devices -l`, then pass a device ID to the
+ script like this:
+
+ ```sh
+ ./android.py test --connected emulator-5554
+ ```
+
+* In `--managed` mode, it uses a temporary headless emulator defined in the
+ `managedDevices` section of testbed/app/build.gradle.kts. This mode is slower,
+ but more reproducible.
+
+ We currently define two devices: `minVersion` and `maxVersion`, corresponding
+ to our minimum and maximum supported Android versions. For example:
+
+ ```sh
+ ./android.py test --managed maxVersion
+ ```
+
+By default, the only messages the script will show are Python's own stdout and
+stderr. Add the `-v` option to also show Gradle output, and non-Python logcat
+messages.
+
+Any other arguments on the `android.py test` command line will be passed through
+to `python -m test` – use `--` to separate them from android.py's own options.
+See the [Python Developer's
+Guide](https://devguide.python.org/testing/run-write-tests/) for common options
+– most of them will work on Android, except for those that involve subprocesses,
+such as `-j`.
+
+Every time you run `android.py test`, changes in pure-Python files in the
+repository's `Lib` directory will be picked up immediately. Changes in C files,
+and architecture-specific files such as sysconfigdata, will not take effect
+until you re-run `android.py make-host` or `build`.
+
+The testbed app can also be used to test third-party packages. For more details,
+run `android.py test --help`, paying attention to the options `--site-packages`,
+`--cwd`, `-c` and `-m`.
+
+
+## Using in your own app
+
+See https://docs.python.org/3/using/android.html.
diff --git a/Android/android-env.sh b/Android/android-env.sh
index 545d559d93ab36c..40381316a2071e0 100644
--- a/Android/android-env.sh
+++ b/Android/android-env.sh
@@ -1,13 +1,13 @@
# This script must be sourced with the following variables already set:
-: ${ANDROID_HOME:?} # Path to Android SDK
-: ${HOST:?} # GNU target triplet
+: "${ANDROID_HOME:?}" # Path to Android SDK
+: "${HOST:?}" # GNU target triplet
# You may also override the following:
-: ${api_level:=21} # Minimum Android API level the build will run on
-: ${PREFIX:-} # Path in which to find required libraries
+: "${ANDROID_API_LEVEL:=21}" # Minimum Android API level the build will run on
+: "${PREFIX:-}" # Path in which to find required libraries
-# Print all messages on stderr so they're visible when running within build-wheel.
+# Print all messages on stderr so they're visible when stdout is captured.
log() {
echo "$1" >&2
}
@@ -24,26 +24,26 @@ fail() {
# * https://android.googlesource.com/platform/ndk/+/ndk-rXX-release/docs/BuildSystemMaintainers.md
# where XX is the NDK version. Do a diff against the version you're upgrading from, e.g.:
# https://android.googlesource.com/platform/ndk/+/ndk-r25-release..ndk-r26-release/docs/BuildSystemMaintainers.md
-ndk_version=26.2.11394342
+ndk_version=27.3.13750724
ndk=$ANDROID_HOME/ndk/$ndk_version
-if ! [ -e $ndk ]; then
- log "Installing NDK: this may take several minutes"
- yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "ndk;$ndk_version"
+if ! [ -e "$ndk/package.xml" ]; then
+ log "Installing NDK - this may take several minutes"
+ yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "ndk;$ndk_version"
fi
-if [ $HOST = "arm-linux-androideabi" ]; then
+if [ "$HOST" = "arm-linux-androideabi" ]; then
clang_triplet=armv7a-linux-androideabi
else
- clang_triplet=$HOST
+ clang_triplet="$HOST"
fi
# These variables are based on BuildSystemMaintainers.md above, and
# $ndk/build/cmake/android.toolchain.cmake.
-toolchain=$(echo $ndk/toolchains/llvm/prebuilt/*)
+toolchain=$(echo "$ndk"/toolchains/llvm/prebuilt/*)
export AR="$toolchain/bin/llvm-ar"
export AS="$toolchain/bin/llvm-as"
-export CC="$toolchain/bin/${clang_triplet}${api_level}-clang"
+export CC="$toolchain/bin/${clang_triplet}${ANDROID_API_LEVEL}-clang"
export CXX="${CC}++"
export LD="$toolchain/bin/ld"
export NM="$toolchain/bin/llvm-nm"
@@ -58,8 +58,8 @@ for path in "$AR" "$AS" "$CC" "$CXX" "$LD" "$NM" "$RANLIB" "$READELF" "$STRIP";
fi
done
-export CFLAGS=""
-export LDFLAGS="-Wl,--build-id=sha1 -Wl,--no-rosegment"
+export CFLAGS="-D__BIONIC_NO_PAGE_SIZE_MACRO"
+export LDFLAGS="-Wl,--build-id=sha1 -Wl,--no-rosegment -Wl,-z,max-page-size=16384"
# Unlike Linux, Android does not implicitly use a dlopened library to resolve
# relocations in subsequently-loaded libraries, even if RTLD_GLOBAL is used
@@ -72,12 +72,12 @@ LDFLAGS="$LDFLAGS -lm"
# -mstackrealign is included where necessary in the clang launcher scripts which are
# pointed to by $CC, so we don't need to include it here.
-if [ $HOST = "arm-linux-androideabi" ]; then
+if [ "$HOST" = "arm-linux-androideabi" ]; then
CFLAGS="$CFLAGS -march=armv7-a -mthumb"
fi
if [ -n "${PREFIX:-}" ]; then
- abs_prefix=$(realpath $PREFIX)
+ abs_prefix="$(realpath "$PREFIX")"
CFLAGS="$CFLAGS -I$abs_prefix/include"
LDFLAGS="$LDFLAGS -L$abs_prefix/lib"
@@ -85,9 +85,15 @@ if [ -n "${PREFIX:-}" ]; then
export PKG_CONFIG_LIBDIR="$abs_prefix/lib/pkgconfig"
fi
+# When compiling C++, some build systems will combine CFLAGS and CXXFLAGS, and some will
+# use CXXFLAGS alone.
+export CXXFLAGS="$CFLAGS"
+
# Use the same variable name as conda-build
-if [ $(uname) = "Darwin" ]; then
- export CPU_COUNT=$(sysctl -n hw.ncpu)
+if [ "$(uname)" = "Darwin" ]; then
+ CPU_COUNT="$(sysctl -n hw.ncpu)"
+ export CPU_COUNT
else
- export CPU_COUNT=$(nproc)
+ CPU_COUNT="$(nproc)"
+ export CPU_COUNT
fi
diff --git a/Android/android.py b/Android/android.py
index 0a1393e61ddb0e6..c5198c96bdd40c7 100755
--- a/Android/android.py
+++ b/Android/android.py
@@ -1,33 +1,107 @@
#!/usr/bin/env python3
+import asyncio
import argparse
+import json
import os
+import platform
import re
+import shlex
import shutil
+import signal
import subprocess
import sys
import sysconfig
-from os.path import basename, relpath
+from asyncio import wait_for
+from contextlib import asynccontextmanager
+from datetime import datetime, timezone
+from enum import IntEnum, auto
+from glob import glob
+from os.path import abspath, basename, relpath
from pathlib import Path
+from subprocess import CalledProcessError
from tempfile import TemporaryDirectory
+
SCRIPT_NAME = Path(__file__).name
-CHECKOUT = Path(__file__).resolve().parent.parent
-CROSS_BUILD_DIR = CHECKOUT / "cross-build"
+ANDROID_DIR = Path(__file__).resolve().parent
+PYTHON_DIR = ANDROID_DIR.parent
+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"
+
+HOSTS = [
+ "aarch64-linux-android",
+ "arm-linux-androideabi",
+ "i686-linux-android",
+ "x86_64-linux-android",
+]
+APP_ID = "org.python.testbed"
+DECODE_ARGS = ("UTF-8", "backslashreplace")
+
+
+try:
+ android_home = Path(os.environ['ANDROID_HOME'])
+except KeyError:
+ sys.exit("The ANDROID_HOME environment variable is required.")
+
+adb = Path(
+ f"{android_home}/platform-tools/adb"
+ + (".exe" if os.name == "nt" else "")
+)
+
+gradlew = Path(
+ f"{TESTBED_DIR}/gradlew"
+ + (".bat" if os.name == "nt" else "")
+)
+
+# Whether we've seen any output from Python yet.
+python_started = False
+
+# Buffer for verbose output which will be displayed only if a test fails and
+# there has been no output from Python.
+hidden_output = []
+
+# Based on android/log.h in the NDK.
+class LogPriority(IntEnum):
+ UNKNOWN = 0
+ DEFAULT = auto()
+ VERBOSE = auto()
+ DEBUG = auto()
+ INFO = auto()
+ WARN = auto()
+ ERROR = auto()
+ FATAL = auto()
+ SILENT = auto()
-def delete_if_exists(path):
- if path.exists():
+
+def log_verbose(context, line, stream=sys.stdout):
+ if context.verbose:
+ stream.write(line)
+ else:
+ hidden_output.append((stream, line))
+
+
+def delete_glob(pattern):
+ # Path.glob doesn't accept non-relative patterns.
+ for path in glob(str(pattern)):
+ path = Path(path)
print(f"Deleting {path} ...")
- shutil.rmtree(path)
+ if path.is_dir() and not path.is_symlink():
+ shutil.rmtree(path)
+ else:
+ path.unlink()
-def subdir(name, *, clean=None):
- path = CROSS_BUILD_DIR / name
- if clean:
- delete_if_exists(path)
+def subdir(*parts, create=False):
+ path = CROSS_BUILD_DIR.joinpath(*parts)
if not path.exists():
- if clean is None:
+ if not create:
sys.exit(
f"{path} does not exist. Create it by running the appropriate "
f"`configure` subcommand of {SCRIPT_NAME}.")
@@ -36,39 +110,69 @@ def subdir(name, *, clean=None):
return path
-def run(command, *, host=None, **kwargs):
- env = os.environ.copy()
+def run(command, *, host=None, env=None, log=True, **kwargs):
+ kwargs.setdefault("check", True)
+ if env is None:
+ env = os.environ.copy()
+
if host:
- env_script = CHECKOUT / "Android/android-env.sh"
- env_output = subprocess.run(
- f"set -eu; "
- f"HOST={host}; "
- f"PREFIX={subdir(host)}/prefix; "
- f". {env_script}; "
- f"export",
- check=True, shell=True, text=True, stdout=subprocess.PIPE
- ).stdout
-
- for line in env_output.splitlines():
- # We don't require every line to match, as there may be some other
- # output from installing the NDK.
- if match := re.search(
- "^(declare -x |export )?(\\w+)=['\"]?(.*?)['\"]?$", line
- ):
- key, value = match[2], match[3]
- if env.get(key) != value:
- print(line)
- env[key] = value
-
- if env == os.environ:
- raise ValueError(f"Found no variables in {env_script.name} output:\n"
- + env_output)
-
- print(">", " ".join(map(str, command)))
- try:
- subprocess.run(command, check=True, env=env, **kwargs)
- except subprocess.CalledProcessError as e:
- sys.exit(e)
+ host_env = android_env(host)
+ print_env(host_env)
+ env.update(host_env)
+
+ if log:
+ print(">", join_command(command))
+ return subprocess.run(command, env=env, **kwargs)
+
+
+# Format a command so it can be copied into a shell. Like shlex.join, but also
+# accepts arguments which are Paths, or a single string/Path outside of a list.
+def join_command(args):
+ if isinstance(args, (str, Path)):
+ return str(args)
+ else:
+ return shlex.join(map(str, args))
+
+
+# Format the environment so it can be pasted into a shell.
+def print_env(env):
+ for key, value in sorted(env.items()):
+ print(f"export {key}={shlex.quote(value)}")
+
+
+def android_env(host):
+ if host:
+ prefix = subdir(host) / "prefix"
+ else:
+ prefix = ANDROID_DIR / "prefix"
+ sysconfig_files = prefix.glob("lib/python*/_sysconfigdata__android_*.py")
+ sysconfig_filename = next(sysconfig_files).name
+ host = re.fullmatch(r"_sysconfigdata__android_(.+).py", sysconfig_filename)[1]
+
+ env_output = subprocess.run(
+ f"set -eu; "
+ f"HOST={host}; "
+ f"PREFIX={prefix}; "
+ f". {ENV_SCRIPT}; "
+ f"export",
+ check=True, shell=True, stdout=subprocess.PIPE, encoding='utf-8',
+ ).stdout
+
+ env = {}
+ for line in env_output.splitlines():
+ # We don't require every line to match, as there may be some other
+ # output from installing the NDK.
+ if match := re.search(
+ "^(declare -x |export )?(\\w+)=['\"]?(.*?)['\"]?$", line
+ ):
+ key, value = match[2], match[3]
+ if os.environ.get(key) != value:
+ env[key] = value
+
+ if not env:
+ raise ValueError(f"Found no variables in {ENV_SCRIPT.name} output:\n"
+ + env_output)
+ return env
def build_python_path():
@@ -85,9 +189,11 @@ def build_python_path():
def configure_build_python(context):
- os.chdir(subdir("build", clean=context.clean))
+ if context.clean:
+ clean("build")
+ os.chdir(subdir("build", create=True))
- command = [relpath(CHECKOUT / "configure")]
+ command = [relpath(PYTHON_DIR / "configure")]
if context.args:
command.extend(context.args)
run(command)
@@ -98,39 +204,64 @@ def make_build_python(context):
run(["make", "-j", str(os.cpu_count())])
-def unpack_deps(host):
+def pythoninfo_build_python(context):
+ os.chdir(subdir("build"))
+ run(["make", "pythoninfo"])
+
+
+# To create new builds of these dependencies, usually all that's necessary is to
+# push a tag to the cpython-android-source-deps repository, and GitHub Actions
+# will do the rest.
+#
+# If you're a member of the Python core team, and you'd like to be able to push
+# these tags yourself, please contact Malcolm Smith or Russell Keith-Magee.
+def unpack_deps(host, prefix_dir, cache_dir):
+ os.chdir(prefix_dir)
deps_url = "https://github.com/beeware/cpython-android-source-deps/releases/download"
- for name_ver in ["bzip2-1.0.8-1", "libffi-3.4.4-2", "openssl-3.0.13-1",
- "sqlite-3.45.1-0", "xz-5.4.6-0"]:
+ for name_ver in [
+ "bzip2-1.0.8-3",
+ "libffi-3.4.4-3",
+ "openssl-3.0.22-0",
+ "sqlite-3.50.4-0",
+ "xz-5.4.6-1"
+ ]:
filename = f"{name_ver}-{host}.tar.gz"
- download(f"{deps_url}/{name_ver}/{filename}")
- run(["tar", "-xf", filename])
- os.remove(filename)
+ out_path = download(f"{deps_url}/{name_ver}/{filename}", cache_dir)
+ shutil.unpack_archive(out_path)
-def download(url, target_dir="."):
- out_path = f"{target_dir}/{basename(url)}"
- run(["curl", "-Lf", "-o", out_path, url])
+def download(url, cache_dir):
+ out_path = cache_dir / basename(url)
+ cache_dir.mkdir(parents=True, exist_ok=True)
+ if not out_path.is_file():
+ run(["curl", "-Lf", "--retry", "5", "--retry-all-errors", "-o", out_path, url])
+ else:
+ print(f"Using cached version of {basename(url)}")
return out_path
-def configure_host_python(context):
- host_dir = subdir(context.host, clean=context.clean)
+def configure_host_python(context, host=None):
+ if host is None:
+ host = context.host
+ if context.clean:
+ clean(host)
+ host_dir = subdir(host, create=True)
prefix_dir = host_dir / "prefix"
if not prefix_dir.exists():
prefix_dir.mkdir()
- os.chdir(prefix_dir)
- unpack_deps(context.host)
-
- build_dir = host_dir / "build"
- build_dir.mkdir(exist_ok=True)
- os.chdir(build_dir)
+ cache_dir = (
+ Path(context.cache_dir).resolve()
+ if context.cache_dir
+ else CROSS_BUILD_DIR / "downloads"
+ )
+ unpack_deps(host, prefix_dir, cache_dir)
+ os.chdir(host_dir)
command = [
# Basic cross-compiling configuration
- relpath(CHECKOUT / "configure"),
- f"--host={context.host}",
+ relpath(PYTHON_DIR / "configure"),
+ f"--host={host}",
f"--build={sysconfig.get_config_var('BUILD_GNU_TYPE')}",
f"--with-build-python={build_python_path()}",
"--without-ensurepip",
@@ -146,91 +277,785 @@ def configure_host_python(context):
if context.args:
command.extend(context.args)
- run(command, host=context.host)
+ run(command, host=host)
+
+
+def make_host_python(context, host=None):
+ if host is None:
+ host = context.host
+ # The CFLAGS and LDFLAGS set in android-env include the prefix dir, so
+ # delete any previous Python installation to prevent it being used during
+ # the build.
+ host_dir = subdir(host)
+ prefix_dir = host_dir / "prefix"
+ for pattern in ("include/python*", "lib/libpython*", "lib/python*"):
+ delete_glob(f"{prefix_dir}/{pattern}")
+
+ # The Android environment variables were already captured in the Makefile by
+ # `configure`, and passing them again when running `make` may cause some
+ # flags to be duplicated. So we don't use the `host` argument here.
+ os.chdir(host_dir)
+ run(["make", "-j", str(os.cpu_count())])
+
+ # The `make install` output is very verbose and rarely useful, so
+ # suppress it by default.
+ run(
+ ["make", "install", f"prefix={prefix_dir}"],
+ capture_output=not context.verbose,
+ )
+
+def build_targets(context):
+ if context.target in {"all", "build"}:
+ configure_build_python(context)
+ make_build_python(context)
+ pythoninfo_build_python(context)
-def make_host_python(context):
- host_dir = subdir(context.host)
- os.chdir(host_dir / "build")
- run(["make", "-j", str(os.cpu_count())], host=context.host)
- run(["make", "install", f"prefix={host_dir}/prefix"], host=context.host)
+ for host in HOSTS:
+ if context.target in {"all", "hosts", host}:
+ configure_host_python(context, host)
+ make_host_python(context, host)
-def build_all(context):
- steps = [configure_build_python, make_build_python, configure_host_python,
- make_host_python]
- for step in steps:
- step(context)
+def clean(host):
+ delete_glob(CROSS_BUILD_DIR / host)
-def clean_all(context):
- delete_if_exists(CROSS_BUILD_DIR)
+def clean_targets(context):
+ if context.target in {"all", "build"}:
+ clean("build")
+
+ for host in HOSTS:
+ if context.target in {"all", "hosts", host}:
+ clean(host)
+
+
+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)
+
+
+def setup_sdk():
+ sdkmanager = android_home / (
+ "cmdline-tools/latest/bin/sdkmanager"
+ + (".bat" if os.name == "nt" else "")
+ )
+
+ # Gradle will fail if it needs to install an SDK package whose license
+ # hasn't been accepted, so pre-accept all licenses.
+ if not all((android_home / "licenses" / path).exists() for path in [
+ "android-sdk-arm-dbt-license", "android-sdk-license"
+ ]):
+ run(
+ [sdkmanager, "--licenses"],
+ text=True,
+ capture_output=True,
+ input="y\n" * 100,
+ )
+
+ # Gradle may install this automatically, but we can't rely on that because
+ # we need to run adb within the logcat task.
+ if not adb.exists():
+ run([sdkmanager, "platform-tools"])
# To avoid distributing compiled artifacts without corresponding source code,
# the Gradle wrapper is not included in the CPython repository. Instead, we
-# extract it from the Gradle release.
-def setup_testbed(context):
- ver_long = "8.7.0"
- ver_short = ver_long.removesuffix(".0")
- testbed_dir = CHECKOUT / "Android/testbed"
-
- for filename in ["gradlew", "gradlew.bat"]:
- out_path = download(
- f"https://raw.githubusercontent.com/gradle/gradle/v{ver_long}/{filename}",
- testbed_dir)
+# extract it from the Gradle GitHub repository.
+def setup_testbed():
+ paths = ["gradlew", "gradlew.bat", "gradle/wrapper/gradle-wrapper.jar"]
+ if all((TESTBED_DIR / path).exists() for path in paths):
+ return
+
+ # Any version of the wrapper can run any reasonably close version of Gradle, so this
+ # doesn't need to match the Gradle version used for the build, which is specified in
+ # testbed/gradle/wrapper/gradle-wrapper.properties.
+ version = "9.5.0"
+
+ for path in paths:
+ out_path = TESTBED_DIR / path
+ out_path.parent.mkdir(exist_ok=True)
+ download(
+ f"https://raw.githubusercontent.com/gradle/gradle/v{version}/{path}",
+ out_path.parent,
+ )
os.chmod(out_path, 0o755)
+
+# Work around a bug involving sys.exit and TaskGroups
+# (https://github.com/python/cpython/issues/101515).
+def exit(*args):
+ raise MySystemExit(*args)
+
+
+class MySystemExit(Exception):
+ pass
+
+
+# The `test` subcommand runs all subprocesses through this context manager so
+# that no matter what happens, they can always be cancelled from another task,
+# and they will always be cleaned up on exit.
+@asynccontextmanager
+async def async_process(*args, **kwargs):
+ process = await asyncio.create_subprocess_exec(*args, **kwargs)
+ try:
+ yield process
+ finally:
+ if process.returncode is None:
+ # Allow a reasonably long time for Gradle to clean itself up,
+ # because we don't want stale emulators left behind.
+ timeout = 10
+ process.terminate()
+ try:
+ await wait_for(process.wait(), timeout)
+ except TimeoutError:
+ print(
+ f"Command {args} did not terminate after {timeout} seconds "
+ f" - sending SIGKILL"
+ )
+ process.kill()
+
+ # Even after killing the process we must still wait for it,
+ # otherwise we'll get the warning "Exception ignored in __del__".
+ await wait_for(process.wait(), timeout=1)
+
+
+async def async_check_output(*args, **kwargs):
+ async with async_process(
+ *args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs
+ ) as process:
+ stdout, stderr = await process.communicate()
+ if process.returncode == 0:
+ return stdout.decode(*DECODE_ARGS)
+ else:
+ raise CalledProcessError(
+ process.returncode, args,
+ stdout.decode(*DECODE_ARGS), stderr.decode(*DECODE_ARGS)
+ )
+
+
+# Return a list of the serial numbers of connected devices. Emulators will have
+# serials of the form "emulator-5678".
+async def list_devices():
+ serials = []
+ header_found = False
+
+ lines = (await async_check_output(adb, "devices")).splitlines()
+ for line in lines:
+ # Ignore blank lines, and all lines before the header.
+ line = line.strip()
+ if line == "List of devices attached":
+ header_found = True
+ elif header_found and line:
+ try:
+ serial, status = line.split()
+ except ValueError:
+ raise ValueError(f"failed to parse {line!r}")
+ if status == "device":
+ serials.append(serial)
+
+ if not header_found:
+ raise ValueError(f"failed to parse {lines}")
+ return serials
+
+
+async def find_device(context, initial_devices):
+ if context.managed:
+ print("Waiting for managed device - this may take several minutes")
+ while True:
+ new_devices = set(await list_devices()).difference(initial_devices)
+ if len(new_devices) == 0:
+ await asyncio.sleep(1)
+ elif len(new_devices) == 1:
+ serial = new_devices.pop()
+ print(f"Serial: {serial}")
+ return serial
+ else:
+ exit(f"Found more than one new device: {new_devices}")
+ else:
+ return context.connected
+
+
+# An older version of this script in #121595 filtered the logs by UID instead.
+# But logcat can't filter by UID until API level 31. If we ever switch back to
+# filtering by UID, we'll also have to filter by time so we only show messages
+# produced after the initial call to `stop_app`.
+#
+# We're more likely to miss the PID because it's shorter-lived, so there's a
+# workaround in PythonSuite.kt to stop it being *too* short-lived.
+async def find_pid(serial):
+ print("Waiting for app to start - this may take several minutes")
+ shown_error = False
+ while True:
+ try:
+ # `pidof` requires API level 24 or higher. The level 23 emulator
+ # includes it, but it doesn't work (it returns all processes).
+ pid = (await async_check_output(
+ adb, "-s", serial, "shell", "pidof", "-s", APP_ID
+ )).strip()
+ except CalledProcessError as e:
+ # If the app isn't running yet, pidof gives no output. So if there
+ # is output, there must have been some other error. However, this
+ # sometimes happens transiently, especially when running a managed
+ # emulator for the first time, so don't make it fatal.
+ if (e.stdout or e.stderr) and not shown_error:
+ print_called_process_error(e)
+ print("This may be transient, so continuing to wait")
+ shown_error = True
+ else:
+ # Some older devices (e.g. Nexus 4) return zero even when no process
+ # was found, so check whether we actually got any output.
+ if pid:
+ print(f"PID: {pid}")
+ return pid
+
+ # Loop fairly rapidly to avoid missing a short-lived process.
+ await asyncio.sleep(0.2)
+
+
+async def logcat_task(context, initial_devices):
+ # Gradle may need to do some large downloads of libraries and emulator
+ # images. This will happen during find_device in --managed mode, or find_pid
+ # in --connected mode.
+ startup_timeout = 600
+ serial = await wait_for(find_device(context, initial_devices), startup_timeout)
+ pid = await wait_for(find_pid(serial), startup_timeout)
+
+ # `--pid` requires API level 24 or higher.
+ #
+ # `--binary` mode is used in order to detect which messages end with a
+ # newline, which most of the other modes don't indicate (except `--format
+ # long`). For example, every time pytest runs a test, it prints a "." and
+ # flushes the stream. Each "." becomes a separate log message, but we should
+ # show them all on the same line.
+ args = [adb, "-s", serial, "logcat", "--pid", pid, "--binary"]
+ logcat_started = False
+ async with async_process(
+ *args, stdout=subprocess.PIPE, stderr=None
+ ) as process:
+ while True:
+ try:
+ priority, tag, message = await read_logcat(process.stdout)
+ logcat_started = True
+ except asyncio.IncompleteReadError:
+ break
+
+ # Exclude high-volume messages which are rarely useful.
+ if context.verbose < 2 and "from python test_syslog" in message:
+ continue
+
+ # Put high-level messages on stderr so they're highlighted in the
+ # buildbot logs. This will include Python's own stderr.
+ stream = sys.stderr if priority >= LogPriority.WARN else sys.stdout
+
+ # The app's stdout and stderr should be passed through transparently
+ # to our own corresponding streams.
+ if tag in ["python.stdout", "python.stderr"]:
+ global python_started
+ python_started = True
+ stream.write(message)
+ stream.flush()
+ else:
+ # Non-Python messages add a lot of noise, but they may
+ # sometimes help explain a failure. Format them in the same way
+ # as `logcat --format tag`.
+ formatted = f"{priority.name[0]}/{tag}: {message}"
+ if not formatted.endswith("\n"):
+ formatted += "\n"
+ log_verbose(context, formatted, stream)
+
+ # If the device disconnects while logcat is running, which always
+ # happens in --managed mode, some versions of adb return non-zero.
+ # Distinguish this from a logcat startup error by checking whether we've
+ # received any logcat messages yet.
+ status = await wait_for(process.wait(), timeout=1)
+ if status != 0 and not logcat_started:
+ raise CalledProcessError(status, args)
+
+
+# Read one binary log message from the given StreamReader. The message format is
+# described at https://android.stackexchange.com/a/74660. All supported versions
+# of Android use format version 2 or later.
+async def read_logcat(stream):
+ async def read_bytes(size):
+ return await stream.readexactly(size)
+
+ async def read_int(size):
+ return int.from_bytes(await read_bytes(size), "little")
+
+ payload_len = await read_int(2)
+ if payload_len < 2:
+ # 1 byte for priority, 1 byte for null terminator of tag.
+ raise ValueError(f"payload length {payload_len} is too short")
+
+ header_len = await read_int(2)
+ if header_len < 4:
+ raise ValueError(f"header length {header_len} is too short")
+ await read_bytes(header_len - 4) # Ignore other header fields.
+
+ priority_int = await read_int(1)
+ try:
+ priority = LogPriority(priority_int)
+ except ValueError:
+ priority = LogPriority.UNKNOWN
+
+ payload = await read_bytes(payload_len - 1)
+ payload_fields = payload.split(b"\0")
+ if len(payload_fields) < 2:
+ raise ValueError(
+ f"payload {payload!r} does not contain at least 2 "
+ f"null-separated fields"
+ )
+ tag, message, *_ = [
+ field.decode(*DECODE_ARGS) for field in payload_fields
+ ]
+ return priority, tag, message
+
+
+def stop_app(serial):
+ run([adb, "-s", serial, "shell", "am", "force-stop", APP_ID], log=False)
+
+
+async def gradle_task(context):
+ env = os.environ.copy()
+ if context.managed:
+ task_prefix = context.managed
+ else:
+ task_prefix = "connected"
+ env["ANDROID_SERIAL"] = context.connected
+
+ # Ensure that CROSS_BUILD_DIR is in the Gradle environment, regardless
+ # of whether it was set by environment variable or `--cross-build-dir`.
+ env["CROSS_BUILD_DIR"] = CROSS_BUILD_DIR
+
+ if context.ci_mode:
+ context.args[0:0] = [
+ # See _add_ci_python_opts in libregrtest/main.py.
+ "-W", "error", "-bb", "-E",
+
+ # Randomization is disabled because order-dependent failures are
+ # much less likely to pass on a rerun in single-process mode.
+ "-m", "test",
+ f"--{context.ci_mode}-ci", "--single-process", "--no-randomize"
+ ]
+
+ if not any(arg in context.args for arg in ["-c", "-m"]):
+ context.args[0:0] = ["-m", "test"]
+
+ args = [
+ gradlew, "--console", "plain", f"{task_prefix}DebugAndroidTest",
+ ] + [
+ f"-P{name}={value}"
+ for name, value in [
+ ("python.sitePackages", context.site_packages),
+ ("python.cwd", context.cwd),
+ (
+ "android.testInstrumentationRunnerArguments.pythonArgs",
+ json.dumps(context.args),
+ ),
+ ]
+ if value
+ ]
+ if context.verbose >= 2:
+ args.append("--info")
+ log_verbose(context, f"> {join_command(args)}\n")
+
+ try:
+ async with async_process(
+ *args, cwd=TESTBED_DIR, env=env,
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+ ) as process:
+ while line := (await process.stdout.readline()).decode(*DECODE_ARGS):
+ # Gradle may take several minutes to install SDK packages, so
+ # it's worth showing those messages even in non-verbose mode.
+ if line.startswith('Preparing "Install'):
+ sys.stdout.write(line)
+ else:
+ log_verbose(context, line)
+
+ status = await wait_for(process.wait(), timeout=1)
+ if status == 0:
+ exit(0)
+ else:
+ raise CalledProcessError(status, args)
+ finally:
+ # Gradle does not stop the tests when interrupted.
+ if context.connected:
+ stop_app(context.connected)
+
+
+async def run_testbed(context):
+ setup_ci()
+ setup_sdk()
+ setup_testbed()
+
+ if context.managed:
+ # In this mode, Gradle will create a device with an unpredictable name.
+ # So we save a list of the running devices before starting Gradle, and
+ # find_device then waits for a new device to appear.
+ initial_devices = await list_devices()
+ else:
+ # In case the previous shutdown was unclean, make sure the app isn't
+ # running, otherwise we might show logs from a previous run. This is
+ # unnecessary in --managed mode, because Gradle creates a new emulator
+ # every time.
+ stop_app(context.connected)
+ initial_devices = None
+
+ try:
+ async with asyncio.TaskGroup() as tg:
+ tg.create_task(logcat_task(context, initial_devices))
+ tg.create_task(gradle_task(context))
+ except* MySystemExit as e:
+ raise SystemExit(*e.exceptions[0].args) from None
+ except* CalledProcessError as e:
+ # If Python produced no output, then the user probably wants to see the
+ # verbose output to explain why the test failed.
+ if not python_started:
+ for stream, line in hidden_output:
+ stream.write(line)
+
+ # Extract it from the ExceptionGroup so it can be handled by `main`.
+ raise e.exceptions[0]
+
+
+def package_version(prefix_dir):
+ patchlevel_glob = f"{prefix_dir}/include/python*/patchlevel.h"
+ patchlevel_paths = glob(patchlevel_glob)
+ if len(patchlevel_paths) != 1:
+ sys.exit(f"{patchlevel_glob} matched {len(patchlevel_paths)} paths.")
+
+ for line in open(patchlevel_paths[0]):
+ if match := re.fullmatch(r'\s*#define\s+PY_VERSION\s+"(.+)"\s*', line):
+ version = match[1]
+ break
+ else:
+ sys.exit(f"Failed to find Python version in {patchlevel_paths[0]}.")
+
+ # If not building against a tagged commit, add a timestamp to the version.
+ # Follow the PyPA version number rules, as this will make it easier to
+ # process with other tools.
+ if version.endswith("+"):
+ version += datetime.now(timezone.utc).strftime("%Y%m%d.%H%M%S")
+
+ return version
+
+
+def package(context):
+ prefix_dir = subdir(context.host, "prefix")
+ version = package_version(prefix_dir)
+
with TemporaryDirectory(prefix=SCRIPT_NAME) as temp_dir:
- os.chdir(temp_dir)
- bin_zip = download(
- f"https://services.gradle.org/distributions/gradle-{ver_short}-bin.zip")
- outer_jar = f"gradle-{ver_short}/lib/plugins/gradle-wrapper-{ver_short}.jar"
- run(["unzip", bin_zip, outer_jar])
- run(["unzip", "-o", "-d", f"{testbed_dir}/gradle/wrapper", outer_jar,
- "gradle-wrapper.jar"])
+ temp_dir = Path(temp_dir)
+ # Include all tracked files from the Android directory.
+ for line in run(
+ ["git", "ls-files"],
+ cwd=ANDROID_DIR, capture_output=True, text=True, log=False,
+ ).stdout.splitlines():
+ src = ANDROID_DIR / line
+ dst = temp_dir / line
+ dst.parent.mkdir(parents=True, exist_ok=True)
+ shutil.copy2(src, dst, follow_symlinks=False)
-def main():
+ # Include anything from the prefix directory which could be useful
+ # either for embedding Python in an app, or building third-party
+ # packages against it.
+ for rel_dir, patterns in [
+ ("include", ["openssl*", "python*", "sqlite*"]),
+ ("lib", ["engines-3", "libcrypto*.so", "libpython*", "libsqlite*",
+ "libssl*.so", "ossl-modules", "python*"]),
+ ("lib/pkgconfig", ["*crypto*", "*ssl*", "*python*", "*sqlite*"]),
+ ]:
+ for pattern in patterns:
+ for src in glob(f"{prefix_dir}/{rel_dir}/{pattern}"):
+ dst = temp_dir / relpath(src, prefix_dir.parent)
+ dst.parent.mkdir(parents=True, exist_ok=True)
+ if Path(src).is_dir():
+ shutil.copytree(
+ src, dst, symlinks=True,
+ ignore=lambda *args: ["__pycache__"]
+ )
+ else:
+ shutil.copy2(src, dst, follow_symlinks=False)
+
+ # Strip debug information.
+ if not context.debug:
+ so_files = glob(f"{temp_dir}/**/*.so", recursive=True)
+ run([android_env(context.host)["STRIP"], *so_files], log=False)
+
+ dist_dir = subdir(context.host, "dist", create=True)
+ package_path = shutil.make_archive(
+ f"{dist_dir}/python-{version}-{context.host}", "gztar", temp_dir
+ )
+ print(f"Wrote {package_path}")
+ return package_path
+
+
+def ci(context):
+ for step in [
+ configure_build_python,
+ make_build_python,
+ pythoninfo_build_python,
+ configure_host_python,
+ make_host_python,
+ package,
+ ]:
+ caption = (
+ step.__name__.replace("_", " ")
+ .capitalize()
+ .replace("python", "Python")
+ )
+ print(f"::group::{caption}")
+ result = step(context)
+ if step is package:
+ package_path = result
+ print("::endgroup::")
+
+ if (
+ "GITHUB_ACTIONS" in os.environ
+ and (platform.system(), platform.machine()) != ("Linux", "x86_64")
+ ):
+ print(
+ "Skipping tests: GitHub Actions does not support the Android "
+ "emulator on this platform."
+ )
+ else:
+ with TemporaryDirectory(prefix=SCRIPT_NAME) as temp_dir:
+ print("::group::Tests")
+
+ # Prove the package is self-contained by using it to run the tests.
+ shutil.unpack_archive(package_path, temp_dir)
+ launcher_args = [
+ "--managed", "maxVersion", "-v", f"--{context.ci_mode}-ci"
+ ]
+ run(
+ ["./android.py", "test", *launcher_args],
+ cwd=temp_dir
+ )
+ print("::endgroup::")
+
+
+def env(context):
+ print_env(android_env(getattr(context, "host", None)))
+
+
+# Handle SIGTERM the same way as SIGINT. This ensures that if we're terminated
+# by the buildbot worker, we'll make an attempt to clean up our subprocesses.
+def install_signal_handler():
+ def signal_handler(*args):
+ os.kill(os.getpid(), signal.SIGINT)
+
+ signal.signal(signal.SIGTERM, signal_handler)
+
+
+def parse_args():
parser = argparse.ArgumentParser()
- subcommands = parser.add_subparsers(dest="subcommand")
- build = subcommands.add_parser("build", help="Build everything")
- configure_build = subcommands.add_parser("configure-build",
- help="Run `configure` for the "
- "build Python")
- make_build = subcommands.add_parser("make-build",
- help="Run `make` for the build Python")
- configure_host = subcommands.add_parser("configure-host",
- help="Run `configure` for Android")
- make_host = subcommands.add_parser("make-host",
- help="Run `make` for Android")
- subcommands.add_parser(
- "clean", help="Delete the cross-build directory")
- subcommands.add_parser(
- "setup-testbed", help="Download the testbed Gradle wrapper")
-
- for subcommand in build, configure_build, configure_host:
+ subcommands = parser.add_subparsers(dest="subcommand", required=True)
+
+ def add_parser(*args, **kwargs):
+ parser = subcommands.add_parser(*args, **kwargs)
+ parser.add_argument(
+ "--cross-build-dir",
+ action="store",
+ default=os.environ.get("CROSS_BUILD_DIR"),
+ dest="cross_build_dir",
+ type=Path,
+ help=(
+ "Path to the cross-build directory "
+ f"(default: {CROSS_BUILD_DIR}). Can also be set "
+ "with the CROSS_BUILD_DIR environment variable."
+ ),
+ )
+ parser.add_argument(
+ "-v", "--verbose", action="count", default=0,
+ help="Show verbose output. Use twice to be even more verbose.")
+ return parser
+
+ # Subcommands
+ build = add_parser(
+ "build",
+ help="Run configure and make for the selected target"
+ )
+ configure_build = add_parser(
+ "configure-build", help="Run `configure` for the build Python")
+ add_parser(
+ "make-build", help="Run `make` for the build Python")
+ add_parser(
+ "pythoninfo-build", help="Display build info of the build Python")
+ configure_host = add_parser(
+ "configure-host", help="Run `configure` for Android")
+ make_host = add_parser(
+ "make-host", help="Run `make` for Android")
+
+ clean = add_parser(
+ "clean",
+ help="Delete build directories for the selected target"
+ )
+
+ test = add_parser("test", help="Run the testbed app")
+ package = add_parser("package", help="Make a release package")
+ ci = add_parser("ci", help="Run build, package and test")
+ env = add_parser("env", help="Print environment variables")
+
+ # Common arguments
+ # --cache-dir option
+ for cmd in [configure_host, build, ci]:
+ cmd.add_argument(
+ "--cache-dir",
+ default=os.environ.get("CACHE_DIR"),
+ help="The directory to store cached downloads.",
+ )
+
+ # --clean option
+ for subcommand in [build, configure_build, configure_host, ci]:
subcommand.add_argument(
"--clean", action="store_true", default=False, dest="clean",
- help="Delete any relevant directories before building")
- for subcommand in build, configure_host, make_host:
+ help="Delete the relevant build directories first")
+
+ # Allow "all", "build" and "hosts" targets for some commands
+ for subcommand in [clean, build]:
subcommand.add_argument(
- "host", metavar="HOST",
- choices=["aarch64-linux-android", "x86_64-linux-android"],
+ "target",
+ nargs="?",
+ default="all",
+ choices=["all", "build", "hosts"] + HOSTS,
+ help=(
+ "The host triplet (e.g., aarch64-linux-android), "
+ "or 'build' for just the build platform, or 'hosts' for all "
+ "host platforms, or 'all' for the build platform and all "
+ "hosts. Defaults to 'all'"
+ ),
+ )
+
+ host_commands = [configure_host, make_host, package, ci]
+ if in_source_tree:
+ host_commands.append(env)
+ for subcommand in host_commands:
+ subcommand.add_argument(
+ "host", metavar="HOST", choices=HOSTS,
help="Host triplet: choices=[%(choices)s]")
- for subcommand in build, configure_build, configure_host:
+
+ for subcommand in [build, configure_build, configure_host, ci]:
subcommand.add_argument("args", nargs="*",
help="Extra arguments to pass to `configure`")
- context = parser.parse_args()
- dispatch = {"configure-build": configure_build_python,
- "make-build": make_build_python,
- "configure-host": configure_host_python,
- "make-host": make_host_python,
- "build": build_all,
- "clean": clean_all,
- "setup-testbed": setup_testbed}
- dispatch[context.subcommand](context)
+ # Test arguments
+ device_group = test.add_mutually_exclusive_group(required=True)
+ device_group.add_argument(
+ "--connected", metavar="SERIAL", help="Run on a connected device. "
+ "Connect it yourself, then get its serial from `adb devices`.")
+ device_group.add_argument(
+ "--managed", metavar="NAME", help="Run on a Gradle-managed device. "
+ "These are defined in `managedDevices` in testbed/app/build.gradle.kts.")
+
+ test.add_argument(
+ "--site-packages", metavar="DIR", type=abspath,
+ help="Directory to copy as the app's site-packages.")
+ test.add_argument(
+ "--cwd", metavar="DIR", type=abspath,
+ help="Directory to copy as the app's working directory.")
+ test.add_argument(
+ "args", nargs="*", help=f"Python command-line arguments. "
+ f"Separate them from {SCRIPT_NAME}'s own arguments with `--`. "
+ f"If neither -c nor -m are included, `-m test` will be prepended, "
+ f"which will run Python's own test suite.")
+
+ # Package arguments.
+ for subcommand in [package, ci]:
+ subcommand.add_argument(
+ "-g", action="store_true", default=False, dest="debug",
+ help="Include debug information in package")
+
+ # CI arguments
+ for subcommand in [test, ci]:
+ group = subcommand.add_mutually_exclusive_group(required=subcommand is ci)
+ 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")
+
+ return parser.parse_args()
+
+
+def main():
+ install_signal_handler()
+
+ # 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)
+
+ context = parse_args()
+
+ # Set the CROSS_BUILD_DIR if an argument was provided
+ if context.cross_build_dir:
+ global CROSS_BUILD_DIR
+ CROSS_BUILD_DIR = context.cross_build_dir.resolve()
+
+ dispatch = {
+ "configure-build": configure_build_python,
+ "make-build": make_build_python,
+ "pythoninfo-build": pythoninfo_build_python,
+ "configure-host": configure_host_python,
+ "make-host": make_host_python,
+ "build": build_targets,
+ "clean": clean_targets,
+ "test": run_testbed,
+ "package": package,
+ "ci": ci,
+ "env": env,
+ }
+
+ try:
+ result = dispatch[context.subcommand](context)
+ if asyncio.iscoroutine(result):
+ asyncio.run(result)
+ except CalledProcessError as e:
+ print_called_process_error(e)
+ sys.exit(1)
+
+
+def print_called_process_error(e):
+ for stream_name in ["stdout", "stderr"]:
+ content = getattr(e, stream_name)
+ if isinstance(content, bytes):
+ content = content.decode(*DECODE_ARGS)
+ stream = getattr(sys, stream_name)
+ if content:
+ stream.write(content)
+ if not content.endswith("\n"):
+ stream.write("\n")
+
+ # shlex uses single quotes, so we surround the command with double quotes.
+ print(
+ f'Command "{join_command(e.cmd)}" returned exit status {e.returncode}'
+ )
if __name__ == "__main__":
diff --git a/Android/testbed/.gitignore b/Android/testbed/.gitignore
index b9a7d611c943cf6..7c57aee58c160a2 100644
--- a/Android/testbed/.gitignore
+++ b/Android/testbed/.gitignore
@@ -1,18 +1,19 @@
-# The Gradle wrapper should be downloaded by running `../android.py setup-testbed`.
+# The Gradle wrapper can be downloaded by running the `test` or `build-testbed`
+# commands of android.py.
/gradlew
/gradlew.bat
/gradle/wrapper/gradle-wrapper.jar
+# The repository's top-level .gitignore file ignores all .idea directories, but
+# we want to keep any files which can't be regenerated from the Gradle
+# configuration.
+!.idea/
+/.idea/*
+!/.idea/inspectionProfiles
+
*.iml
.gradle
/local.properties
-/.idea/caches
-/.idea/deploymentTargetDropdown.xml
-/.idea/libraries
-/.idea/modules.xml
-/.idea/workspace.xml
-/.idea/navEditor.xml
-/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
diff --git a/Android/testbed/.idea/inspectionProfiles/Project_Default.xml b/Android/testbed/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 000000000000000..220d9ed4ef20f7c
--- /dev/null
+++ b/Android/testbed/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Android/testbed/app/build.gradle.kts b/Android/testbed/app/build.gradle.kts
index 7690d3fd86b2fdf..e724ba7dbc9d1ce 100644
--- a/Android/testbed/app/build.gradle.kts
+++ b/Android/testbed/app/build.gradle.kts
@@ -1,59 +1,193 @@
import com.android.build.api.variant.*
+import kotlin.math.max
plugins {
id("com.android.application")
- id("org.jetbrains.kotlin.android")
}
-val PYTHON_DIR = File(projectDir, "../../..").canonicalPath
-val PYTHON_CROSS_DIR = "$PYTHON_DIR/cross-build"
-val ABIS = mapOf(
- "arm64-v8a" to "aarch64-linux-android",
- "x86_64" to "x86_64-linux-android",
+val ANDROID_DIR = file("../..")
+val PYTHON_DIR = ANDROID_DIR.parentFile!!
+val PYTHON_CROSS_DIR = file(System.getenv("CROSS_BUILD_DIR") ?: "$PYTHON_DIR/cross-build")
+val inSourceTree = (
+ ANDROID_DIR.name == "Android" && file("$PYTHON_DIR/pyconfig.h.in").exists()
)
-val PYTHON_VERSION = File("$PYTHON_DIR/Include/patchlevel.h").useLines {
- for (line in it) {
- val match = """#define PY_VERSION\s+"(\d+\.\d+)""".toRegex().find(line)
- if (match != null) {
- return@useLines match.groupValues[1]
+val KNOWN_ABIS = mapOf(
+ "aarch64-linux-android" to "arm64-v8a",
+ "arm-linux-androideabi" to "armeabi-v7a",
+ "i686-linux-android" to "x86",
+ "x86_64-linux-android" to "x86_64",
+)
+
+val osArch = System.getProperty("os.arch")
+val NATIVE_ABI = mapOf(
+ "aarch64" to "arm64-v8a",
+ "amd64" to "x86_64",
+ "arm64" to "arm64-v8a",
+ "x86_64" to "x86_64",
+)[osArch] ?: throw GradleException("Unknown os.arch '$osArch'")
+
+// Discover prefixes.
+val prefixes = ArrayList()
+if (inSourceTree) {
+ for ((triplet, _) in KNOWN_ABIS.entries) {
+ val prefix = file("$PYTHON_CROSS_DIR/$triplet/prefix")
+ if (prefix.exists()) {
+ prefixes.add(prefix)
}
}
- throw GradleException("Failed to find Python version")
+} else {
+ // Testbed is inside a release package.
+ val prefix = file("$ANDROID_DIR/prefix")
+ if (prefix.exists()) {
+ prefixes.add(prefix)
+ }
+}
+if (prefixes.isEmpty()) {
+ throw GradleException(
+ "No Android prefixes found: see README.md for testing instructions"
+ )
+}
+
+// Detect Python versions and ABIs.
+lateinit var pythonVersion: String
+var abis = HashMap()
+for ((i, prefix) in prefixes.withIndex()) {
+ val libDir = file("$prefix/lib")
+ val version = run {
+ for (filename in libDir.list()!!) {
+ """python(\d+\.\d+[a-z]*)""".toRegex().matchEntire(filename)?.let {
+ return@run it.groupValues[1]
+ }
+ }
+ throw GradleException("Failed to find Python version in $libDir")
+ }
+ if (i == 0) {
+ pythonVersion = version
+ } else if (pythonVersion != version) {
+ throw GradleException(
+ "${prefixes[0]} is Python $pythonVersion, but $prefix is Python $version"
+ )
+ }
+
+ 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]
+ }
+ }
+ throw GradleException("Failed to find Python triplet in $libPythonDir")
+ }
+ abis[prefix] = KNOWN_ABIS[triplet]!!
}
android {
+ val androidEnvFile = file("../../android-env.sh").absoluteFile
+
namespace = "org.python.testbed"
- compileSdk = 34
+ compileSdk = 35
defaultConfig {
applicationId = "org.python.testbed"
- minSdk = 21
- targetSdk = 34
+
+ minSdk = androidEnvFile.useLines {
+ for (line in it) {
+ """ANDROID_API_LEVEL:=(\d+)""".toRegex().find(line)?.let {
+ return@useLines it.groupValues[1].toInt()
+ }
+ }
+ throw GradleException("Failed to find API level in $androidEnvFile")
+ }
+
+ // This controls the API level of the maxVersion managed emulator, which is used
+ // by CI and cibuildwheel.
+ // * 32 has intermittent failures accessing the internet (#142387).
+ // * 33 has excessive buffering in the logcat client
+ // (https://cs.android.com/android/_/android/platform/system/logging/+/d340721894f223327339010df59b0ac514308826).
+ // * 34 consumes too much disk space on GitHub Actions (#142289), though switching to the
+ // "default" image may be a workaround.
+ // * 36 and later are not available as aosp_atd images yet.
+ targetSdk = 35
+
versionCode = 1
versionName = "1.0"
- ndk.abiFilters.addAll(ABIS.keys)
+ ndk.abiFilters.addAll(abis.values)
externalNativeBuild.cmake.arguments(
- "-DPYTHON_CROSS_DIR=$PYTHON_CROSS_DIR",
- "-DPYTHON_VERSION=$PYTHON_VERSION")
+ "-DPYTHON_PREFIX_DIR=" + if (inSourceTree) {
+ // AGP uses the ${} syntax for its own purposes, so use a Jinja style
+ // placeholder.
+ "$PYTHON_CROSS_DIR/{{triplet}}/prefix"
+ } else {
+ prefixes[0]
+ },
+ "-DPYTHON_VERSION=$pythonVersion",
+ "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON",
+ )
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
+ ndkVersion = androidEnvFile.useLines {
+ for (line in it) {
+ """ndk_version=(\S+)""".toRegex().find(line)?.let {
+ return@useLines it.groupValues[1]
+ }
+ }
+ throw GradleException("Failed to find NDK version in $androidEnvFile")
+ }
externalNativeBuild.cmake {
path("src/main/c/CMakeLists.txt")
}
- // Set this property to something non-empty, otherwise it'll use the default
- // list, which ignores asset directories beginning with an underscore.
- aaptOptions.ignoreAssetsPattern = ".git"
-
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
- kotlinOptions {
- jvmTarget = "1.8"
+
+ testOptions {
+ managedDevices {
+ localDevices {
+ // systemImageSource should use what its documentation calls an
+ // "explicit source", i.e. the sdkmanager package name format, because
+ // that will be required in CreateEmulatorTask below.
+ create("minVersion") {
+ device = "Small Phone"
+
+ // Managed devices have a minimum API level of 27.
+ apiLevel = max(27, defaultConfig.minSdk!!)
+
+ // ATD devices are smaller and faster, but have a minimum
+ // API level of 30.
+ systemImageSource = if (apiLevel >= 30) "aosp_atd" else "default"
+ }
+
+ create("maxVersion") {
+ device = "Small Phone"
+ apiLevel = defaultConfig.targetSdk!!
+ systemImageSource = "aosp_atd"
+ }
+ }
+
+ // If the previous test run succeeded and nothing has changed,
+ // Gradle thinks there's no need to run it again. Override that.
+ afterEvaluate {
+ (localDevices.names + listOf("connected")).forEach {
+ tasks.named("${it}DebugAndroidTest") {
+ outputs.upToDateWhen { false }
+ }
+ }
+ }
+ }
+ }
+ androidResources {
+ // Set this property to something nonexistent but non-empty. Otherwise it'll use
+ // the default list, which ignores asset directories beginning with an
+ // underscore, and maybe also other files required by tests.
+ ignoreAssetsPattern = "android-testbed-dont-ignore-anything"
}
}
@@ -61,41 +195,205 @@ dependencies {
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
+ androidTestImplementation("androidx.test.ext:junit:1.1.5")
+ androidTestImplementation("androidx.test:rules:1.5.0")
+}
+
+
+afterEvaluate {
+ // Every new emulator has a maximum of 2 GB RAM, regardless of its hardware profile
+ // (https://cs.android.com/android-studio/platform/tools/base/+/refs/tags/studio-2025.3.2:sdklib/src/main/java/com/android/sdklib/internal/avd/EmulatedProperties.java;l=68).
+ // This is barely enough to test Python, and not enough to test Pandas
+ // (https://github.com/python/cpython/pull/137186#issuecomment-3136301023,
+ // https://github.com/pandas-dev/pandas/pull/63405#issuecomment-3667846159).
+ // So we'll increase it by editing the emulator configuration files.
+ //
+ // If the emulator doesn't exist yet, we want to edit it after it's created, but
+ // before it starts for the first time. Otherwise it'll need to be cold-booted
+ // again, which would slow down the first run, which is likely the only run in CI
+ // environments. But the Setup task both creates and starts the emulator if it
+ // doesn't already exist. So we create it ourselves before the Setup task runs.
+ for (device in android.testOptions.managedDevices.localDevices) {
+ val createTask = tasks.register("${device.name}Create") {
+ this.device = device.device
+ apiLevel = device.apiLevel
+ systemImageSource = device.systemImageSource
+ abi = NATIVE_ABI
+ }
+ tasks.named("${device.name}Setup") {
+ dependsOn(createTask)
+ }
+ }
+}
+
+abstract class CreateEmulatorTask : DefaultTask() {
+ @get:Input abstract val device: Property
+ @get:Input abstract val apiLevel: Property
+ @get:Input abstract val systemImageSource: Property
+ @get:Input abstract val abi: Property
+ @get:Inject abstract val execOps: ExecOperations
+
+ private val avdName by lazy {
+ listOf(
+ "dev${apiLevel.get()}",
+ systemImageSource.get(),
+ abi.get(),
+ device.get().replace(' ', '_'),
+ ).joinToString("_")
+ }
+
+ private val avdDir by lazy {
+ // XDG_CONFIG_HOME is respected by both avdmanager and Gradle.
+ val userHome = System.getenv("ANDROID_USER_HOME") ?: (
+ (System.getenv("XDG_CONFIG_HOME") ?: System.getProperty("user.home")!!)
+ + "/.android"
+ )
+ File("$userHome/avd/gradle-managed", "$avdName.avd")
+ }
+
+ @TaskAction
+ fun run() {
+ if (!avdDir.exists()) {
+ createAvd()
+ }
+ updateAvd()
+ }
+
+ fun createAvd() {
+ val systemImage = listOf(
+ "system-images",
+ "android-${apiLevel.get()}",
+ systemImageSource.get(),
+ abi.get(),
+ ).joinToString(";")
+
+ runCmdlineTool("sdkmanager", systemImage)
+ runCmdlineTool(
+ "avdmanager", "create", "avd",
+ "--name", avdName,
+ "--path", avdDir,
+ "--device", device.get().lowercase().replace(" ", "_"),
+ "--package", systemImage,
+ )
+
+ val iniName = "$avdName.ini"
+ if (!File(avdDir.parentFile.parentFile, iniName).renameTo(
+ File(avdDir.parentFile, iniName)
+ )) {
+ throw GradleException("Failed to rename $iniName")
+ }
+ }
+
+ fun updateAvd() {
+ for (filename in listOf(
+ "config.ini", // Created by avdmanager; always exists
+ "hardware-qemu.ini", // Created on first run; might not exist
+ )) {
+ val iniFile = File(avdDir, filename)
+ if (!iniFile.exists()) {
+ if (filename == "config.ini") {
+ throw GradleException("$iniFile does not exist")
+ }
+ continue
+ }
+
+ val iniText = iniFile.readText()
+ val pattern = Regex(
+ """^\s*hw.ramSize\s*=\s*(.+?)\s*$""", RegexOption.MULTILINE
+ )
+ val matches = pattern.findAll(iniText).toList()
+ if (matches.size != 1) {
+ throw GradleException(
+ "Found ${matches.size} instances of $pattern in $iniFile; expected 1"
+ )
+ }
+
+ val expectedRam = "4096"
+ if (matches[0].groupValues[1] != expectedRam) {
+ iniFile.writeText(
+ iniText.replace(pattern, "hw.ramSize = $expectedRam")
+ )
+ }
+ }
+ }
+
+ fun runCmdlineTool(tool: String, vararg args: Any) {
+ val androidHome = System.getenv("ANDROID_HOME")!!
+ val exeSuffix =
+ if (System.getProperty("os.name").lowercase().startsWith("win")) ".exe"
+ else ""
+ val command =
+ listOf("$androidHome/cmdline-tools/latest/bin/$tool$exeSuffix", *args)
+ println(command.joinToString(" "))
+ execOps.exec {
+ commandLine(command)
+ }
+ }
}
// Create some custom tasks to copy Python and its standard library from
// elsewhere in the repository.
androidComponents.onVariants { variant ->
+ val pyPlusVer = "python$pythonVersion"
generateTask(variant, variant.sources.assets!!) {
into("python") {
- for (triplet in ABIS.values) {
- for (subDir in listOf("include", "lib")) {
- into(subDir) {
- from("$PYTHON_CROSS_DIR/$triplet/prefix/$subDir")
- include("python$PYTHON_VERSION/**")
- duplicatesStrategy = DuplicatesStrategy.EXCLUDE
- }
+ // Include files such as pyconfig.h are used by some of the tests.
+ into("include/$pyPlusVer") {
+ for (prefix in prefixes) {
+ from("$prefix/include/$pyPlusVer")
}
+ duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
- into("lib/python$PYTHON_VERSION") {
- // Uncomment this to pick up edits from the source directory
- // without having to rerun `make install`.
- // from("$PYTHON_DIR/Lib")
- // duplicatesStrategy = DuplicatesStrategy.INCLUDE
+
+ into("lib/$pyPlusVer") {
+ // To aid debugging, the source directory takes priority when
+ // running inside a CPython source tree.
+ if (inSourceTree) {
+ from("$PYTHON_DIR/Lib")
+ }
+ for (prefix in prefixes) {
+ from("$prefix/lib/$pyPlusVer")
+ }
into("site-packages") {
from("$projectDir/src/main/python")
+
+ val sitePackages = findProperty("python.sitePackages") as String?
+ if (!sitePackages.isNullOrEmpty()) {
+ if (!file(sitePackages).exists()) {
+ throw GradleException("$sitePackages does not exist")
+ }
+ from(sitePackages)
+ }
+ }
+
+ duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+ exclude("**/__pycache__")
+ }
+
+ into("cwd") {
+ val cwd = findProperty("python.cwd") as String?
+ if (!cwd.isNullOrEmpty()) {
+ if (!file(cwd).exists()) {
+ throw GradleException("$cwd does not exist")
+ }
+ from(cwd)
}
}
+
+ // A filename ending with .gz will be automatically decompressed
+ // while building the APK. Avoid this by adding a dash to the end,
+ // and add an extra dash to any filenames that already end with one.
+ // This will be undone in MainActivity.kt.
+ rename(""".*(\.gz|-)""", "$0-")
}
- exclude("**/__pycache__")
}
generateTask(variant, variant.sources.jniLibs!!) {
- for ((abi, triplet) in ABIS.entries) {
+ for ((prefix, abi) in abis.entries) {
into(abi) {
- from("$PYTHON_CROSS_DIR/$triplet/prefix/lib")
+ from("$prefix/lib")
include("libpython*.*.so")
include("lib*_python.so")
}
diff --git a/Android/testbed/app/src/androidTest/java/org/python/testbed/PythonSuite.kt b/Android/testbed/app/src/androidTest/java/org/python/testbed/PythonSuite.kt
new file mode 100644
index 000000000000000..e57243566f91dca
--- /dev/null
+++ b/Android/testbed/app/src/androidTest/java/org/python/testbed/PythonSuite.kt
@@ -0,0 +1,35 @@
+package org.python.testbed
+
+import androidx.test.annotation.UiThreadTest
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+
+@RunWith(AndroidJUnit4::class)
+class PythonSuite {
+ @Test
+ @UiThreadTest
+ fun testPython() {
+ val start = System.currentTimeMillis()
+ try {
+ val status = PythonTestRunner(
+ InstrumentationRegistry.getInstrumentation().targetContext
+ ).run(
+ InstrumentationRegistry.getArguments().getString("pythonArgs")!!,
+ )
+ assertEquals(0, status)
+ } finally {
+ // Make sure the process lives long enough for the test script to
+ // detect it (see `find_pid` in android.py).
+ val delay = 2000 - (System.currentTimeMillis() - start)
+ if (delay > 0) {
+ Thread.sleep(delay)
+ }
+ }
+ }
+}
diff --git a/Android/testbed/app/src/main/c/CMakeLists.txt b/Android/testbed/app/src/main/c/CMakeLists.txt
index 1d5df9a73465b6e..6d5ccd96f8ae290 100644
--- a/Android/testbed/app/src/main/c/CMakeLists.txt
+++ b/Android/testbed/app/src/main/c/CMakeLists.txt
@@ -1,9 +1,14 @@
cmake_minimum_required(VERSION 3.4.1)
project(testbed)
-set(PREFIX_DIR ${PYTHON_CROSS_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}/prefix)
-include_directories(${PREFIX_DIR}/include/python${PYTHON_VERSION})
-link_directories(${PREFIX_DIR}/lib)
+# Resolve variables from the command line.
+string(
+ REPLACE {{triplet}} ${CMAKE_LIBRARY_ARCHITECTURE}
+ PYTHON_PREFIX_DIR ${PYTHON_PREFIX_DIR}
+)
+
+include_directories(${PYTHON_PREFIX_DIR}/include/python${PYTHON_VERSION})
+link_directories(${PYTHON_PREFIX_DIR}/lib)
link_libraries(log python${PYTHON_VERSION})
add_library(main_activity SHARED main_activity.c)
diff --git a/Android/testbed/app/src/main/c/main_activity.c b/Android/testbed/app/src/main/c/main_activity.c
index 73aba4164d000f7..7f024f0a348b61c 100644
--- a/Android/testbed/app/src/main/c/main_activity.c
+++ b/Android/testbed/app/src/main/c/main_activity.c
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -15,6 +16,13 @@ static void throw_runtime_exception(JNIEnv *env, const char *message) {
message);
}
+static void throw_errno(JNIEnv *env, const char *error_prefix) {
+ char error_message[1024];
+ snprintf(error_message, sizeof(error_message),
+ "%s: %s", error_prefix, strerror(errno));
+ throw_runtime_exception(env, error_message);
+}
+
// --- Stdio redirection ------------------------------------------------------
@@ -34,9 +42,12 @@ typedef struct {
int pipe[2];
} StreamInfo;
+// The FILE member can't be initialized here because stdout and stderr are not
+// compile-time constants. Instead, it's initialized immediately before the
+// redirection.
static StreamInfo STREAMS[] = {
- {stdout, STDOUT_FILENO, ANDROID_LOG_INFO, "native.stdout", {-1, -1}},
- {stderr, STDERR_FILENO, ANDROID_LOG_WARN, "native.stderr", {-1, -1}},
+ {NULL, STDOUT_FILENO, ANDROID_LOG_INFO, "native.stdout", {-1, -1}},
+ {NULL, STDERR_FILENO, ANDROID_LOG_WARN, "native.stderr", {-1, -1}},
{NULL, -1, ANDROID_LOG_UNKNOWN, NULL, {-1, -1}},
};
@@ -84,64 +95,108 @@ static char *redirect_stream(StreamInfo *si) {
return 0;
}
-JNIEXPORT void JNICALL Java_org_python_testbed_MainActivity_redirectStdioToLogcat(
+JNIEXPORT void JNICALL Java_org_python_testbed_PythonTestRunner_redirectStdioToLogcat(
JNIEnv *env, jobject obj
) {
+ STREAMS[0].file = stdout;
+ STREAMS[1].file = stderr;
for (StreamInfo *si = STREAMS; si->file; si++) {
char *error_prefix;
if ((error_prefix = redirect_stream(si))) {
- char error_message[1024];
- snprintf(error_message, sizeof(error_message),
- "%s: %s", error_prefix, strerror(errno));
- throw_runtime_exception(env, error_message);
+ throw_errno(env, error_prefix);
return;
}
}
}
-// --- Python intialization ----------------------------------------------------
-
-static PyStatus set_config_string(
- JNIEnv *env, PyConfig *config, wchar_t **config_str, jstring value
-) {
- const char *value_utf8 = (*env)->GetStringUTFChars(env, value, NULL);
- PyStatus status = PyConfig_SetBytesString(config, config_str, value_utf8);
- (*env)->ReleaseStringUTFChars(env, value, value_utf8);
- return status;
+// --- Python initialization ---------------------------------------------------
+
+static char *init_signals() {
+ // Some tests use SIGUSR1, but that's blocked by default in an Android app in
+ // order to make it available to `sigwait` in the Signal Catcher thread.
+ // (https://cs.android.com/android/platform/superproject/+/android14-qpr3-release:art/runtime/signal_catcher.cc).
+ // That thread's functionality is only useful for debugging the JVM, so disabling
+ // it should not weaken the tests.
+ //
+ // There's no safe way of stopping the thread completely (#123982), but simply
+ // unblocking SIGUSR1 is enough to fix most tests.
+ //
+ // However, in tests that generate multiple different signals in quick
+ // succession, it's possible for SIGUSR1 to arrive while the main thread is busy
+ // running the C-level handler for a different signal. In that case, the SIGUSR1
+ // may be sent to the Signal Catcher thread instead, which will generate a log
+ // message containing the text "reacting to signal".
+ //
+ // Such tests may need to be changed in one of the following ways:
+ // * Use a signal other than SIGUSR1 (e.g. test_stress_delivery_simultaneous in
+ // test_signal.py).
+ // * Send the signal to a specific thread rather than the whole process (e.g.
+ // test_signals in test_threadsignals.py.
+ sigset_t set;
+ if (sigemptyset(&set)) {
+ return "sigemptyset";
+ }
+ if (sigaddset(&set, SIGUSR1)) {
+ return "sigaddset";
+ }
+ if ((errno = pthread_sigmask(SIG_UNBLOCK, &set, NULL))) {
+ return "pthread_sigmask";
+ }
+ return NULL;
}
static void throw_status(JNIEnv *env, PyStatus status) {
throw_runtime_exception(env, status.err_msg ? status.err_msg : "");
}
-JNIEXPORT void JNICALL Java_org_python_testbed_MainActivity_runPython(
- JNIEnv *env, jobject obj, jstring home, jstring runModule
+JNIEXPORT int JNICALL Java_org_python_testbed_PythonTestRunner_runPython(
+ JNIEnv *env, jobject obj, jstring home, jarray args
) {
+ const char *home_utf8 = (*env)->GetStringUTFChars(env, home, NULL);
+ char cwd[PATH_MAX];
+ snprintf(cwd, sizeof(cwd), "%s/%s", home_utf8, "cwd");
+ if (chdir(cwd)) {
+ throw_errno(env, "chdir");
+ return 1;
+ }
+
+ char *error_prefix;
+ if ((error_prefix = init_signals())) {
+ throw_errno(env, error_prefix);
+ return 1;
+ }
+
PyConfig config;
PyStatus status;
- PyConfig_InitIsolatedConfig(&config);
+ PyConfig_InitPythonConfig(&config);
- status = set_config_string(env, &config, &config.home, home);
- if (PyStatus_Exception(status)) {
+ jsize argc = (*env)->GetArrayLength(env, args);
+ const char *argv[argc + 1];
+ for (int i = 0; i < argc; i++) {
+ jobject arg = (*env)->GetObjectArrayElement(env, args, i);
+ argv[i] = (*env)->GetStringUTFChars(env, arg, NULL);
+ }
+ argv[argc] = NULL;
+
+ // PyConfig_SetBytesArgv "must be called before other methods, since the
+ // preinitialization configuration depends on command line arguments"
+ if (PyStatus_Exception(status = PyConfig_SetBytesArgv(&config, argc, (char**)argv))) {
throw_status(env, status);
- return;
+ return 1;
}
- status = set_config_string(env, &config, &config.run_module, runModule);
+ status = PyConfig_SetBytesString(&config, &config.home, home_utf8);
if (PyStatus_Exception(status)) {
throw_status(env, status);
- return;
+ return 1;
}
- // Some tests generate SIGPIPE and SIGXFSZ, which should be ignored.
- config.install_signal_handlers = 1;
-
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
throw_status(env, status);
- return;
+ return 1;
}
- Py_RunMain();
+ return Py_RunMain();
}
diff --git a/Android/testbed/app/src/main/java/org/python/testbed/MainActivity.kt b/Android/testbed/app/src/main/java/org/python/testbed/MainActivity.kt
index 5a590d5d04e9542..c8fe3acd849ac7a 100644
--- a/Android/testbed/app/src/main/java/org/python/testbed/MainActivity.kt
+++ b/Android/testbed/app/src/main/java/org/python/testbed/MainActivity.kt
@@ -1,38 +1,68 @@
package org.python.testbed
+import android.content.Context
import android.os.*
import android.system.Os
import android.widget.TextView
import androidx.appcompat.app.*
+import org.json.JSONArray
import java.io.*
+
+// Launching the tests from an activity is OK for a quick check, but for
+// anything more complicated it'll be more convenient to use `android.py test`
+// to launch the tests via PythonSuite.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
+ val status = PythonTestRunner(this).run("""["-m", "test", "-W", "-uall"]""")
+ findViewById(R.id.tvHello).text = "Exit status $status"
+ }
+}
+
+
+class PythonTestRunner(val context: Context) {
+ /** Run Python.
+ *
+ * @param args Python command-line, encoded as JSON.
+ * @return The Python exit status: zero on success, nonzero on failure. */
+ fun run(args: String) : Int {
+ // Argument 0 is a placeholder for the executable name in embedded mode.
+ val argsJsonArray = JSONArray(args)
+ val argsStringArray = Array(argsJsonArray.length() + 1) { i ->
+ if (i == 0) ""
+ else argsJsonArray.getString(i - 1)
+ }
// Python needs this variable to help it find the temporary directory,
// but Android only sets it on API level 33 and later.
- Os.setenv("TMPDIR", cacheDir.toString(), false)
+ Os.setenv("TMPDIR", context.cacheDir.toString(), false)
val pythonHome = extractAssets()
System.loadLibrary("main_activity")
redirectStdioToLogcat()
- runPython(pythonHome.toString(), "main")
- findViewById(R.id.tvHello).text = "Python complete"
+ return runPython(pythonHome.toString(), argsStringArray)
}
private fun extractAssets() : File {
- val pythonHome = File(filesDir, "python")
+ val pythonHome = File(context.filesDir, "python")
if (pythonHome.exists() && !pythonHome.deleteRecursively()) {
throw RuntimeException("Failed to delete $pythonHome")
}
- extractAssetDir("python", filesDir)
+ extractAssetDir("python", context.filesDir)
+
+ // Empty directories are lost in the asset packing/unpacking process.
+ val cwd = File(pythonHome, "cwd")
+ if (!cwd.exists()) {
+ cwd.mkdir()
+ }
+
return pythonHome
}
private fun extractAssetDir(path: String, targetDir: File) {
- val names = assets.list(path)
+ val names = context.assets.list(path)
?: throw RuntimeException("Failed to list $path")
val targetSubdir = File(targetDir, path)
if (!targetSubdir.mkdirs()) {
@@ -43,13 +73,15 @@ class MainActivity : AppCompatActivity() {
val subPath = "$path/$name"
val input: InputStream
try {
- input = assets.open(subPath)
+ input = context.assets.open(subPath)
} catch (e: FileNotFoundException) {
extractAssetDir(subPath, targetDir)
continue
}
input.use {
- File(targetSubdir, name).outputStream().use { output ->
+ // Undo the .gz workaround from build.gradle.kts.
+ val outputName = name.replace(Regex("""(.*)-"""), "$1")
+ File(targetSubdir, outputName).outputStream().use { output ->
input.copyTo(output)
}
}
@@ -57,5 +89,5 @@ class MainActivity : AppCompatActivity() {
}
private external fun redirectStdioToLogcat()
- private external fun runPython(home: String, runModule: String)
-}
\ No newline at end of file
+ private external fun runPython(home: String, args: Array) : Int
+}
diff --git a/Android/testbed/app/src/main/python/main.py b/Android/testbed/app/src/main/python/main.py
deleted file mode 100644
index a1b6def34ede811..000000000000000
--- a/Android/testbed/app/src/main/python/main.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import runpy
-import signal
-import sys
-
-# Some tests use SIGUSR1, but that's blocked by default in an Android app in
-# order to make it available to `sigwait` in the "Signal Catcher" thread. That
-# thread's functionality is only relevant to the JVM ("forcing GC (no HPROF) and
-# profile save"), so disabling it should not weaken the tests.
-signal.pthread_sigmask(signal.SIG_UNBLOCK, [signal.SIGUSR1])
-
-# To run specific tests, or pass any other arguments to the test suite, edit
-# this command line.
-sys.argv[1:] = [
- "--use", "all,-cpu",
- "--verbose3",
-]
-runpy.run_module("test")
diff --git a/Android/testbed/build.gradle.kts b/Android/testbed/build.gradle.kts
index 53f4a67287fcc57..3c48be4bb585139 100644
--- a/Android/testbed/build.gradle.kts
+++ b/Android/testbed/build.gradle.kts
@@ -1,5 +1,4 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
- id("com.android.application") version "8.2.2" apply false
- id("org.jetbrains.kotlin.android") version "1.9.22" apply false
-}
\ No newline at end of file
+ id("com.android.application") version "9.3.1" apply false
+}
diff --git a/Android/testbed/gradle.properties b/Android/testbed/gradle.properties
index 3c5031eb7d63f78..22821df51100134 100644
--- a/Android/testbed/gradle.properties
+++ b/Android/testbed/gradle.properties
@@ -11,13 +11,10 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
-# AndroidX package structure to make it clearer which packages are bundled with the
-# Android operating system, and which are packaged with your app's APK
-# https://developer.android.com/topic/libraries/support-library/androidx-rn
-android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
-# Enables namespacing of each library's R class so that its R class includes only the
-# resources declared in the library itself and none from the library's dependencies,
-# thereby reducing the size of the R class for that library
-android.nonTransitiveRClass=true
\ No newline at end of file
+
+# By default, the app will be uninstalled after the tests finish (apparently
+# after 10 seconds in case of an unclean shutdown). We disable this, because
+# when using android.py it can conflict with the installation of the next run.
+android.injected.androidTest.leaveApksInstalledAfterRun=true
diff --git a/Android/testbed/gradle/wrapper/gradle-wrapper.properties b/Android/testbed/gradle/wrapper/gradle-wrapper.properties
index 2dc3339a3ef2130..6632d9e5c1c4045 100644
--- a/Android/testbed/gradle/wrapper/gradle-wrapper.properties
+++ b/Android/testbed/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Mon Feb 19 20:29:06 GMT 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/Doc/.ruff.toml b/Doc/.ruff.toml
new file mode 100644
index 000000000000000..3e676e13c3f41ac
--- /dev/null
+++ b/Doc/.ruff.toml
@@ -0,0 +1,41 @@
+extend = "../.ruff.toml" # Inherit the project-wide settings
+
+target-version = "py312" # Align with the version in oldest_supported_sphinx
+extend-exclude = [
+ "includes/*",
+ # Temporary exclusions:
+ "tools/extensions/pyspecific.py",
+]
+
+[lint]
+preview = true
+select = [
+ "C4", # flake8-comprehensions
+ "B", # flake8-bugbear
+ "E", # pycodestyle
+ "F", # pyflakes
+ "FA", # flake8-future-annotations
+ "FLY", # flynt
+ "FURB", # refurb
+ "G", # flake8-logging-format
+ "I", # isort
+ "LOG", # flake8-logging
+ "N", # pep8-naming
+ "PERF", # perflint
+ "PGH", # pygrep-hooks
+ "PT", # flake8-pytest-style
+ "TCH", # flake8-type-checking
+ "UP", # pyupgrade
+ "W", # pycodestyle
+]
+ignore = [
+ "E501", # Ignore line length errors (we use auto-formatting)
+]
+
+[format]
+preview = true
+quote-style = "preserve"
+docstring-code-format = true
+exclude = [
+ "tools/extensions/lexers/*",
+]
diff --git a/Doc/Makefile b/Doc/Makefile
index dd068c520ad60cf..60ffcd286e3c820 100644
--- a/Doc/Makefile
+++ b/Doc/Makefile
@@ -6,6 +6,7 @@
# You can set these variables from the command line.
PYTHON = python3
VENVDIR = ./venv
+UV = uv
SPHINXBUILD = PATH=$(VENVDIR)/bin:$$PATH sphinx-build
BLURB = PATH=$(VENVDIR)/bin:$$PATH blurb
JOBS = auto
@@ -13,15 +14,15 @@ PAPER =
SOURCES =
DISTVERSION = $(shell $(PYTHON) tools/extensions/patchlevel.py)
REQUIREMENTS = requirements.txt
-SPHINXERRORHANDLING = -W
+SPHINXERRORHANDLING = --fail-on-warning
# Internal variables.
-PAPEROPT_a4 = -D latex_elements.papersize=a4paper
-PAPEROPT_letter = -D latex_elements.papersize=letterpaper
+PAPEROPT_a4 = --define latex_elements.papersize=a4paper
+PAPEROPT_letter = --define latex_elements.papersize=letterpaper
-ALLSPHINXOPTS = -b $(BUILDER) \
- -d build/doctrees \
- -j $(JOBS) \
+ALLSPHINXOPTS = --builder $(BUILDER) \
+ --doctree-dir build/doctrees \
+ --jobs $(JOBS) \
$(PAPEROPT_$(PAPER)) \
$(SPHINXOPTS) $(SPHINXERRORHANDLING) \
. build/$(BUILDER) $(SOURCES)
@@ -32,6 +33,7 @@ help:
@echo " clean to remove build files"
@echo " venv to create a venv with necessary tools"
@echo " html to make standalone HTML files"
+ @echo " gettext to generate POT files"
@echo " htmlview to open the index page built by the html target in your browser"
@echo " htmllive to rebuild and reload HTML files in your browser"
@echo " htmlhelp to make HTML files and a HTML help project"
@@ -56,7 +58,7 @@ build:
@if [ -f ../Misc/NEWS ] ; then \
echo "Using existing Misc/NEWS file"; \
cp ../Misc/NEWS build/NEWS; \
- elif $(BLURB) help >/dev/null 2>&1 && $(SPHINXBUILD) --version >/dev/null 2>&1; then \
+ elif $(BLURB) --version && $(SPHINXBUILD) --version ; then \
if [ -d ../Misc/NEWS.d ]; then \
echo "Building NEWS from Misc/NEWS.d with blurb"; \
$(BLURB) merge -f build/NEWS; \
@@ -138,16 +140,22 @@ 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/topics.py ../Lib/pydoc_data/topics.py" \
+ "&& cp build/pydoc-topics/module_docs.py ../Lib/pydoc_data/module_docs.py"
+
+.PHONY: gettext
+gettext: BUILDER = gettext
+gettext: override SPHINXOPTS := --doctree-dir build/doctrees-gettext $(SPHINXOPTS)
+gettext: build
.PHONY: htmlview
htmlview: html
$(PYTHON) -c "import os, webbrowser; webbrowser.open('file://' + os.path.realpath('build/html/index.html'))"
.PHONY: htmllive
-htmllive: SPHINXBUILD = $(VENVDIR)/bin/sphinx-autobuild
+htmllive: SPHINXBUILD = PATH=$(VENVDIR)/bin:$$PATH sphinx-autobuild
htmllive: SPHINXOPTS = --re-ignore="/venv/" --open-browser --delay 0
-htmllive: html
+htmllive: _ensure-sphinx-autobuild html
.PHONY: clean
clean: clean-venv
@@ -163,93 +171,153 @@ venv:
echo "venv already exists."; \
echo "To recreate it, remove it first with \`make clean-venv'."; \
else \
+ set -e; \
echo "Creating venv in $(VENVDIR)"; \
- $(PYTHON) -m venv $(VENVDIR); \
- $(VENVDIR)/bin/python3 -m pip install --upgrade pip; \
- $(VENVDIR)/bin/python3 -m pip install -r $(REQUIREMENTS); \
+ if $(UV) --version >/dev/null 2>&1; then \
+ $(UV) venv --python=$(PYTHON) $(VENVDIR); \
+ VIRTUAL_ENV=$(VENVDIR) $(UV) pip install -r $(REQUIREMENTS); \
+ else \
+ $(PYTHON) -m venv $(VENVDIR); \
+ $(VENVDIR)/bin/python3 -m pip install --upgrade pip; \
+ $(VENVDIR)/bin/python3 -m pip install -r $(REQUIREMENTS); \
+ fi; \
echo "The venv has been created in the $(VENVDIR) directory"; \
fi
+.PHONY: dist-no-html
+dist-no-html: dist-text dist-epub dist-texinfo
+
.PHONY: dist
dist:
rm -rf dist
mkdir -p dist
-
+ $(MAKE) dist-html
+ $(MAKE) dist-text
+ $(MAKE) dist-pdf
+ $(MAKE) dist-epub
+ $(MAKE) dist-texinfo
+
+.PHONY: dist-html
+dist-html:
# archive the HTML
- make html
+ @echo "Building HTML..."
+ mkdir -p dist
+ rm -rf build/html
+ find dist -name 'python-$(DISTVERSION)-docs-html*' -exec rm -rf {} \;
+ $(MAKE) html
cp -pPR build/html dist/python-$(DISTVERSION)-docs-html
+ rm -rf dist/python-$(DISTVERSION)-docs-html/_images/social_previews/
tar -C dist -cf dist/python-$(DISTVERSION)-docs-html.tar python-$(DISTVERSION)-docs-html
bzip2 -9 -k dist/python-$(DISTVERSION)-docs-html.tar
(cd dist; zip -q -r -9 python-$(DISTVERSION)-docs-html.zip python-$(DISTVERSION)-docs-html)
rm -r dist/python-$(DISTVERSION)-docs-html
rm dist/python-$(DISTVERSION)-docs-html.tar
+ @echo "Build finished and archived!"
+.PHONY: dist-text
+dist-text:
# archive the text build
- make text
+ @echo "Building text..."
+ mkdir -p dist
+ rm -rf build/text
+ find dist -name 'python-$(DISTVERSION)-docs-text*' -exec rm -rf {} \;
+ $(MAKE) text
cp -pPR build/text dist/python-$(DISTVERSION)-docs-text
tar -C dist -cf dist/python-$(DISTVERSION)-docs-text.tar python-$(DISTVERSION)-docs-text
bzip2 -9 -k dist/python-$(DISTVERSION)-docs-text.tar
(cd dist; zip -q -r -9 python-$(DISTVERSION)-docs-text.zip python-$(DISTVERSION)-docs-text)
rm -r dist/python-$(DISTVERSION)-docs-text
rm dist/python-$(DISTVERSION)-docs-text.tar
+ @echo "Build finished and archived!"
+.PHONY: dist-pdf
+dist-pdf:
# archive the A4 latex
+ @echo "Building LaTeX (A4 paper)..."
+ mkdir -p dist
rm -rf build/latex
- make latex PAPER=a4
- -sed -i 's/makeindex/makeindex -q/' build/latex/Makefile
- (cd build/latex; make clean && make all-pdf && make FMT=pdf zip bz2)
+ find dist -name 'python-$(DISTVERSION)-docs-pdf*' -exec rm -rf {} \;
+ $(MAKE) latex PAPER=a4
+ # remove zip & bz2 dependency on all-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)
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!"
- # archive the letter latex
- rm -rf build/latex
- make latex PAPER=letter
- -sed -i 's/makeindex/makeindex -q/' build/latex/Makefile
- (cd build/latex; make clean && make all-pdf && make FMT=pdf zip bz2)
- cp build/latex/docs-pdf.zip dist/python-$(DISTVERSION)-docs-pdf-letter.zip
- cp build/latex/docs-pdf.tar.bz2 dist/python-$(DISTVERSION)-docs-pdf-letter.tar.bz2
-
+.PHONY: dist-epub
+dist-epub:
# copy the epub build
+ @echo "Building EPUB..."
+ mkdir -p dist
rm -rf build/epub
- make epub
+ rm -f dist/python-$(DISTVERSION)-docs.epub
+ $(MAKE) epub
cp -pPR build/epub/Python.epub dist/python-$(DISTVERSION)-docs.epub
+ @echo "Build finished and archived!"
+.PHONY: dist-texinfo
+dist-texinfo:
# archive the texinfo build
+ @echo "Building Texinfo..."
+ mkdir -p dist
rm -rf build/texinfo
- make texinfo
- make info --directory=build/texinfo
+ find dist -name 'python-$(DISTVERSION)-docs-texinfo*' -exec rm -rf {} \;
+ $(MAKE) texinfo
+ $(MAKE) info --directory=build/texinfo
cp -pPR build/texinfo dist/python-$(DISTVERSION)-docs-texinfo
tar -C dist -cf dist/python-$(DISTVERSION)-docs-texinfo.tar python-$(DISTVERSION)-docs-texinfo
bzip2 -9 -k dist/python-$(DISTVERSION)-docs-texinfo.tar
(cd dist; zip -q -r -9 python-$(DISTVERSION)-docs-texinfo.zip python-$(DISTVERSION)-docs-texinfo)
rm -r dist/python-$(DISTVERSION)-docs-texinfo
rm dist/python-$(DISTVERSION)-docs-texinfo.tar
+ @echo "Build finished and archived!"
+
+.PHONY: _ensure-package
+_ensure-package: venv
+ if $(UV) --version >/dev/null 2>&1; then \
+ VIRTUAL_ENV=$(VENVDIR) $(UV) pip install $(PACKAGE); \
+ else \
+ $(VENVDIR)/bin/python3 -m pip install $(PACKAGE); \
+ fi
+
+.PHONY: _ensure-pre-commit
+_ensure-pre-commit:
+ $(MAKE) _ensure-package PACKAGE=pre-commit
+
+.PHONY: _ensure-sphinx-autobuild
+_ensure-sphinx-autobuild:
+ $(MAKE) _ensure-package PACKAGE=sphinx-autobuild
.PHONY: check
-check: venv
- $(VENVDIR)/bin/python3 -m pre_commit --version > /dev/null || $(VENVDIR)/bin/python3 -m pip install pre-commit
+check: _ensure-pre-commit
$(VENVDIR)/bin/python3 -m pre_commit run --all-files
.PHONY: serve
serve:
- @echo "The serve target was removed, use htmlview instead (see bpo-36329)"
+ @echo "The serve target was removed, use htmllive instead (see gh-80510)"
# Targets for daily automated doc build
# By default, Sphinx only rebuilds pages where the page content has changed.
# This means it doesn't always pick up changes to preferred link targets, etc
# To ensure such changes are picked up, we build the published docs with
-# `-E` (to ignore the cached environment) and `-a` (to ignore already existing
-# output files)
+# ``--fresh-env`` (to ignore the cached environment) and ``--write-all``
+# (to ignore already existing output files)
# for development releases: always build
.PHONY: autobuild-dev
+autobuild-dev: DISTVERSION = $(shell $(PYTHON) tools/extensions/patchlevel.py --short)
autobuild-dev:
- make dist SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1'
+ $(MAKE) dist-no-html SPHINXOPTS='$(SPHINXOPTS) --fresh-env --write-all --html-define daily=1' DISTVERSION=$(DISTVERSION)
-# for quick rebuilds (HTML only)
+# for HTML-only rebuilds
.PHONY: autobuild-dev-html
+autobuild-dev-html: DISTVERSION = $(shell $(PYTHON) tools/extensions/patchlevel.py --short)
autobuild-dev-html:
- make html SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1'
+ $(MAKE) dist-html SPHINXOPTS='$(SPHINXOPTS) --fresh-env --write-all --html-define daily=1' DISTVERSION=$(DISTVERSION)
# for stable releases: only build if not in pre-release stage (alpha, beta)
# release candidate downloads are okay, since the stable tree can be in that stage
@@ -259,7 +327,7 @@ autobuild-stable:
echo "Not building; $(DISTVERSION) is not a release version."; \
exit 1;; \
esac
- @make autobuild-dev
+ @$(MAKE) autobuild-dev
.PHONY: autobuild-stable-html
autobuild-stable-html:
@@ -267,4 +335,4 @@ autobuild-stable-html:
echo "Not building; $(DISTVERSION) is not a release version."; \
exit 1;; \
esac
- @make autobuild-dev-html
+ @$(MAKE) autobuild-dev-html
diff --git a/Doc/README.rst b/Doc/README.rst
index a3bb5fa5445c23a..2d1148753e0c6bb 100644
--- a/Doc/README.rst
+++ b/Doc/README.rst
@@ -28,7 +28,7 @@ install the tools into there.
Using make
----------
-To get started on UNIX, you can create a virtual environment and build
+To get started on Unix, you can create a virtual environment and build
documentation with the commands::
make venv
@@ -40,13 +40,13 @@ If you'd like to create the virtual environment in a different location,
you can specify it using the ``VENVDIR`` variable.
You can also skip creating the virtual environment altogether, in which case
-the Makefile will look for instances of ``sphinx-build`` and ``blurb``
+the ``Makefile`` will look for instances of ``sphinx-build`` and ``blurb``
installed on your process ``PATH`` (configurable with the ``SPHINXBUILD`` and
``BLURB`` variables).
-On Windows, we try to emulate the Makefile as closely as possible with a
+On Windows, we try to emulate the ``Makefile`` as closely as possible with a
``make.bat`` file. If you need to specify the Python interpreter to use,
-set the PYTHON environment variable.
+set the ``PYTHON`` environment variable.
Available make targets are:
@@ -62,15 +62,19 @@ Available make targets are:
* "htmlview", which re-uses the "html" builder, but then opens the main page
in your default web browser.
+* "htmllive", which re-uses the "html" builder, rebuilds the docs,
+ starts a local server, and automatically reloads the page in your browser
+ when you make changes to reST files (Unix only).
+
* "htmlhelp", which builds HTML files and a HTML Help project file usable to
convert them into a single Compiled HTML (.chm) file -- these are popular
under Microsoft Windows, but very handy on every platform.
To create the CHM file, you need to run the Microsoft HTML Help Workshop
- over the generated project (.hhp) file. The make.bat script does this for
+ over the generated project (.hhp) file. The ``make.bat`` script does this for
you on Windows.
-* "latex", which builds LaTeX source files as input to "pdflatex" to produce
+* "latex", which builds LaTeX source files as input to ``pdflatex`` to produce
PDF documents.
* "text", which builds a plain text file for each source file.
@@ -95,8 +99,6 @@ Available make targets are:
* "check", which checks for frequent markup errors.
-* "serve", which serves the build/html directory on port 8000.
-
* "dist", (Unix only) which creates distributable archives of HTML, text,
PDF, and EPUB builds.
@@ -131,8 +133,5 @@ Bugs in the content should be reported to the
Bugs in the toolset should be reported to the tools themselves.
-You can also send a mail to the Python Documentation Team at docs@python.org,
-and we will process your request as soon as possible.
-
-If you want to help the Documentation Team, you are always welcome. Just send
-a mail to docs@python.org.
+To help with the documentation, or report any problems, please leave a message
+on `discuss.python.org `_.
diff --git a/Doc/about.rst b/Doc/about.rst
index 5e6160ff2700ed1..f0dba08130e2c01 100644
--- a/Doc/about.rst
+++ b/Doc/about.rst
@@ -1,15 +1,16 @@
-=====================
-About these documents
-=====================
+========================
+About this documentation
+========================
-These documents are generated from `reStructuredText`_ sources by `Sphinx`_, a
-document processor specifically written for the Python documentation.
+Python's documentation is generated from `reStructuredText`_ sources
+using `Sphinx`_, a documentation generator originally created for Python
+and now maintained as an independent project.
.. _reStructuredText: https://docutils.sourceforge.io/rst.html
.. _Sphinx: https://www.sphinx-doc.org/
-.. In the online version of these documents, you can submit comments and suggest
+.. In the online version of this documentation, you can submit comments and suggest
changes directly on the documentation pages.
Development of the documentation and its toolchain is an entirely volunteer
@@ -20,14 +21,14 @@ volunteers are always welcome!
Many thanks go to:
* Fred L. Drake, Jr., the creator of the original Python documentation toolset
- and writer of much of the content;
+ and author of much of the content;
* the `Docutils `_ project for creating
reStructuredText and the Docutils suite;
* Fredrik Lundh for his Alternative Python Reference project from which Sphinx
got many good ideas.
-Contributors to the Python Documentation
+Contributors to the Python documentation
----------------------------------------
Many people have contributed to the Python language, the Python standard
diff --git a/Doc/bugs.rst b/Doc/bugs.rst
index 9aff2f0ff5187df..9f2b9876ba51dc9 100644
--- a/Doc/bugs.rst
+++ b/Doc/bugs.rst
@@ -9,28 +9,29 @@ stability. In order to maintain this reputation, the developers would like to
know of any deficiencies you find in Python.
It can be sometimes faster to fix bugs yourself and contribute patches to
-Python as it streamlines the process and involves less people. Learn how to
+Python as it streamlines the process and involves fewer people. Learn how to
:ref:`contribute `.
Documentation bugs
==================
If you find a bug in this documentation or would like to propose an improvement,
-please submit a bug report on the :ref:`tracker `. If you
+please submit a bug report on the :ref:`issue 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 `_ instead.
+
You can also open a discussion item on our
`Documentation Discourse forum `_.
If you find a bug in the theme (HTML / CSS / JavaScript) of the
-documentation, please submit a bug report on the `python-doc-theme bug
+documentation, please submit a bug report on the `python-doc-theme issue
tracker `_.
-If you're short on time, you can also email documentation bug reports to
-docs@python.org (behavioral bugs can be sent to python-list@python.org).
-'docs@' is a mailing list run by volunteers; your request will be noticed,
-though it may take a while to be processed.
-
.. seealso::
`Documentation bugs`_
diff --git a/Doc/library/constants.rst b/Doc/builtins/constants.rst
similarity index 73%
rename from Doc/library/constants.rst
rename to Doc/builtins/constants.rst
index 93a7244f87de6b9..6aa703ec259d6fb 100644
--- a/Doc/library/constants.rst
+++ b/Doc/builtins/constants.rst
@@ -22,7 +22,7 @@ A small number of constants live in the built-in namespace. They are:
An object frequently used to represent the absence of a value, as when
default arguments are not passed to a function. Assignments to ``None``
are illegal and raise a :exc:`SyntaxError`.
- ``None`` is the sole instance of the :data:`~types.NoneType` type.
+ ``None`` is the sole instance of the :class:`~types.NoneType` type.
.. data:: NotImplemented
@@ -33,7 +33,7 @@ A small number of constants live in the built-in namespace. They are:
the other type; may be returned by the in-place binary special methods
(e.g. :meth:`~object.__imul__`, :meth:`~object.__iand__`, etc.) for the same purpose.
It should not be evaluated in a boolean context.
- :data:`!NotImplemented` is the sole instance of the :data:`types.NotImplementedType` type.
+ :data:`!NotImplemented` is the sole instance of the :class:`types.NotImplementedType` type.
.. note::
@@ -46,11 +46,12 @@ A small number of constants live in the built-in namespace. They are:
See :ref:`implementing-the-arithmetic-operations` for examples.
- .. note::
+ .. caution::
- ``NotImplementedError`` and :data:`!NotImplemented` are not interchangeable,
- even though they have similar names and purposes.
- See :exc:`NotImplementedError` for details on when to use it.
+ :data:`!NotImplemented` and :exc:`!NotImplementedError` are not
+ interchangeable. This constant should only be used as described
+ above; see :exc:`NotImplementedError` for details on correct usage
+ of the exception.
.. versionchanged:: 3.9
Evaluating :data:`!NotImplemented` in a boolean context is deprecated. While
@@ -61,9 +62,10 @@ A small number of constants live in the built-in namespace. They are:
.. index:: single: ...; ellipsis literal
.. data:: Ellipsis
- The same as the ellipsis literal "``...``". Special value used mostly in conjunction
- with extended slicing syntax for user-defined container data types.
- ``Ellipsis`` is the sole instance of the :data:`types.EllipsisType` type.
+ The same as the ellipsis literal "``...``", an object frequently used to
+ indicate that something is omitted. Assignment to ``Ellipsis`` is possible, but
+ assignment to ``...`` raises a :exc:`SyntaxError`.
+ ``Ellipsis`` is the sole instance of the :class:`types.EllipsisType` type.
.. data:: __debug__
@@ -79,6 +81,8 @@ A small number of constants live in the built-in namespace. They are:
:exc:`SyntaxError`), so they can be considered "true" constants.
+.. _site-consts:
+
Constants added by the :mod:`site` module
-----------------------------------------
@@ -91,9 +95,18 @@ should not be used in programs.
exit(code=None)
Objects that when printed, print a message like "Use quit() or Ctrl-D
- (i.e. EOF) to exit", and when called, raise :exc:`SystemExit` with the
+ (i.e. EOF) to exit", and when accessed directly in the interactive
+ interpreter or called as functions, raise :exc:`SystemExit` with the
specified exit code.
+.. data:: help
+ :noindex:
+
+ Object that when printed, prints the message "Type help() for interactive
+ help, or help(object) for help about object.", and when accessed directly
+ in the interactive interpreter, invokes the built-in help system
+ (see :func:`help`).
+
.. data:: copyright
credits
diff --git a/Doc/library/exceptions.rst b/Doc/builtins/exceptions.rst
similarity index 94%
rename from Doc/library/exceptions.rst
rename to Doc/builtins/exceptions.rst
index 7879fb015bddfa3..df80bfaceca7aac 100644
--- a/Doc/library/exceptions.rst
+++ b/Doc/builtins/exceptions.rst
@@ -204,10 +204,16 @@ The following exceptions are the exceptions that are usually raised.
assignment fails. (When an object does not support attribute references or
attribute assignments at all, :exc:`TypeError` is raised.)
- The :attr:`name` and :attr:`obj` attributes can be set using keyword-only
- arguments to the constructor. When set they represent the name of the attribute
- that was attempted to be accessed and the object that was accessed for said
- attribute, respectively.
+ The optional *name* and *obj* keyword-only arguments
+ set the corresponding attributes:
+
+ .. attribute:: name
+
+ The name of the attribute that was attempted to be accessed.
+
+ .. attribute:: obj
+
+ The object that was accessed for the named attribute.
.. versionchanged:: 3.10
Added the :attr:`name` and :attr:`obj` attributes.
@@ -215,7 +221,7 @@ The following exceptions are the exceptions that are usually raised.
.. exception:: EOFError
Raised when the :func:`input` function hits an end-of-file condition (EOF)
- without reading any data. (N.B.: the :meth:`io.IOBase.read` and
+ without reading any data. (Note: the :meth:`io.TextIOBase.read` and
:meth:`io.IOBase.readline` methods return an empty string when they hit EOF.)
@@ -312,9 +318,11 @@ The following exceptions are the exceptions that are usually raised.
unqualified names. The associated value is an error message that includes the
name that could not be found.
- The :attr:`name` attribute can be set using a keyword-only argument to the
- constructor. When set it represent the name of the variable that was attempted
- to be accessed.
+ The optional *name* keyword-only argument sets the attribute:
+
+ .. attribute:: name
+
+ The name of the variable that was attempted to be accessed.
.. versionchanged:: 3.10
Added the :attr:`name` attribute.
@@ -333,11 +341,13 @@ The following exceptions are the exceptions that are usually raised.
meant to be supported at all -- in that case either leave the operator /
method undefined or, if a subclass, set it to :data:`None`.
- .. note::
+ .. caution::
+
+ :exc:`!NotImplementedError` and :data:`!NotImplemented` are not
+ interchangeable. This exception should only be used as described
+ above; see :data:`NotImplemented` for details on correct usage of
+ the built-in constant.
- ``NotImplementedError`` and :data:`NotImplemented` are not interchangeable,
- even though they have similar names and purposes. See
- :data:`!NotImplemented` for details on when to use it.
.. exception:: OSError([arg])
OSError(errno, strerror[, filename[, winerror[, filename2]]])
@@ -380,7 +390,7 @@ The following exceptions are the exceptions that are usually raised.
The corresponding error message, as provided by
the operating system. It is formatted by the C
- functions :c:func:`perror` under POSIX, and :c:func:`FormatMessage`
+ functions :c:func:`!perror` under POSIX, and :c:func:`!FormatMessage`
under Windows.
.. attribute:: filename
@@ -396,7 +406,7 @@ The following exceptions are the exceptions that are usually raised.
.. versionchanged:: 3.3
:exc:`EnvironmentError`, :exc:`IOError`, :exc:`WindowsError`,
:exc:`socket.error`, :exc:`select.error` and
- :exc:`mmap.error` have been merged into :exc:`OSError`, and the
+ :exc:`!mmap.error` have been merged into :exc:`OSError`, and the
constructor may return a subclass.
.. versionchanged:: 3.4
@@ -412,8 +422,8 @@ The following exceptions are the exceptions that are usually raised.
represented. This cannot occur for integers (which would rather raise
:exc:`MemoryError` than give up). However, for historical reasons,
OverflowError is sometimes raised for integers that are outside a required
- range. Because of the lack of standardization of floating point exception
- handling in C, most floating point operations are not checked.
+ range. Because of the lack of standardization of floating-point exception
+ handling in C, most floating-point operations are not checked.
.. exception:: PythonFinalizationError
@@ -562,9 +572,13 @@ The following exceptions are the exceptions that are usually raised.
Raised when the interpreter finds an internal error, but the situation does not
look so serious to cause it to abandon all hope. The associated value is a
- string indicating what went wrong (in low-level terms).
+ string indicating what went wrong (in low-level terms). In :term:`CPython`,
+ this could be raised by incorrectly using Python's C API, such as returning
+ a ``NULL`` value without an exception set.
- You should report this to the author or maintainer of your Python interpreter.
+ If you're confident that this exception wasn't your fault, or the fault of
+ a package you're using, you should report this to the author or maintainer
+ of your Python interpreter.
Be sure to report the version of the Python interpreter (``sys.version``; it is
also printed at the start of an interactive Python session), the exact error
message (the exception's associated value) and if possible the source of the
@@ -580,7 +594,7 @@ The following exceptions are the exceptions that are usually raised.
handled, the Python interpreter exits; no stack traceback is printed. The
constructor accepts the same optional argument passed to :func:`sys.exit`.
If the value is an integer, it specifies the system exit status (passed to
- C's :c:func:`exit` function); if it is ``None``, the exit status is zero; if
+ C's :c:func:`!exit` function); if it is ``None``, the exit status is zero; if
it has another type (such as a string), the object's value is printed and
the exit status is one.
@@ -711,8 +725,8 @@ depending on the system error code.
.. attribute:: characters_written
- An integer containing the number of characters written to the stream
- before it blocked. This attribute is available when using the
+ An integer containing the number of **bytes** written to the stream
+ before it blocked. This attribute is available when using the
buffered I/O classes from the :mod:`io` module.
.. exception:: ChildProcessError
@@ -866,6 +880,9 @@ The following exceptions are used as warning categories; see the
Base class for warnings about dubious syntax.
+ This warning is typically emitted when compiling Python source code, and usually won't be reported
+ when running already compiled code.
+
.. exception:: RuntimeWarning
@@ -944,6 +961,15 @@ their subgroups based on the types of the contained exceptions.
raises a :exc:`TypeError` if any contained exception is not an
:exc:`Exception` subclass.
+ Exception groups are :ref:`generic ` over the type of their
+ contained exceptions.
+
+ .. impl-detail::
+
+ The ``excs`` parameter may be any sequence, but lists and tuples are
+ specifically processed more efficiently here. For optimal performance,
+ pass a tuple as ``excs``.
+
.. attribute:: message
The ``msg`` argument to the constructor. This is a read-only attribute.
@@ -989,7 +1015,8 @@ their subgroups based on the types of the contained exceptions.
Returns an exception group with the same :attr:`message`, but which
wraps the exceptions in ``excs``.
- This method is used by :meth:`subgroup` and :meth:`split`. A
+ This method is used by :meth:`subgroup` and :meth:`split`, which
+ are used in various contexts to break up an exception group. A
subclass needs to override it in order to make :meth:`subgroup`
and :meth:`split` return instances of the subclass rather
than :exc:`ExceptionGroup`.
@@ -1031,7 +1058,7 @@ their subgroups based on the types of the contained exceptions.
subclasses that need a different constructor signature need to
override that rather than :meth:`~object.__init__`. For example, the following
defines an exception group subclass which accepts an exit_code and
- and constructs the group's message from it. ::
+ constructs the group's message from it. ::
class Errors(ExceptionGroup):
def __new__(cls, errors, exit_code):
diff --git a/Doc/library/functions.rst b/Doc/builtins/functions.rst
similarity index 82%
rename from Doc/library/functions.rst
rename to Doc/builtins/functions.rst
index 0c7ef67774cd057..bf2c8d70120f2d7 100644
--- a/Doc/library/functions.rst
+++ b/Doc/builtins/functions.rst
@@ -54,15 +54,15 @@ are always available. They are listed here in alphabetical order.
.. |func-bytearray| replace:: ``bytearray()``
.. |func-bytes| replace:: ``bytes()``
-.. function:: abs(x)
+.. function:: abs(number, /)
Return the absolute value of a number. The argument may be an
- integer, a floating point number, or an object implementing
+ integer, a floating-point number, or an object implementing
:meth:`~object.__abs__`.
If the argument is a complex number, its magnitude is returned.
-.. function:: aiter(async_iterable)
+.. function:: aiter(async_iterable, /)
Return an :term:`asynchronous iterator` for an :term:`asynchronous iterable`.
Equivalent to calling ``x.__aiter__()``.
@@ -71,7 +71,7 @@ are always available. They are listed here in alphabetical order.
.. versionadded:: 3.10
-.. function:: all(iterable)
+.. function:: all(iterable, /)
Return ``True`` if all elements of the *iterable* are true (or if the iterable
is empty). Equivalent to::
@@ -83,8 +83,8 @@ are always available. They are listed here in alphabetical order.
return True
-.. awaitablefunction:: anext(async_iterator)
- anext(async_iterator, default)
+.. awaitablefunction:: anext(async_iterator, /)
+ anext(async_iterator, default, /)
When awaited, return the next item from the given :term:`asynchronous
iterator`, or *default* if given and the iterator is exhausted.
@@ -99,7 +99,7 @@ are always available. They are listed here in alphabetical order.
.. versionadded:: 3.10
-.. function:: any(iterable)
+.. function:: any(iterable, /)
Return ``True`` if any element of the *iterable* is true. If the iterable
is empty, return ``False``. Equivalent to::
@@ -111,7 +111,7 @@ are always available. They are listed here in alphabetical order.
return False
-.. function:: ascii(object)
+.. function:: ascii(object, /)
As :func:`repr`, return a string containing a printable representation of an
object, but escape the non-ASCII characters in the string returned by
@@ -119,10 +119,10 @@ are always available. They are listed here in alphabetical order.
similar to that returned by :func:`repr` in Python 2.
-.. function:: bin(x)
+.. function:: bin(integer, /)
Convert an integer number to a binary string prefixed with "0b". The result
- is a valid Python expression. If *x* is not a Python :class:`int` object, it
+ is a valid Python expression. If *integer* is not a Python :class:`int` object, it
has to define an :meth:`~object.__index__` method that returns an integer. Some
examples:
@@ -138,13 +138,16 @@ are always available. They are listed here in alphabetical order.
>>> f'{14:#b}', f'{14:b}'
('0b1110', '1110')
+ See also :func:`enum.bin` to represent negative values as twos-complement.
+
See also :func:`format` for more information.
-.. class:: bool(x=False)
+.. class:: bool(object=False, /)
- Return a Boolean value, i.e. one of ``True`` or ``False``. *x* is converted
- using the standard :ref:`truth testing procedure `. If *x* is false
+ Return a Boolean value, i.e. one of ``True`` or ``False``. The argument
+ is converted using the standard :ref:`truth testing procedure `.
+ If the argument is false
or omitted, this returns ``False``; otherwise, it returns ``True``. The
:class:`bool` class is a subclass of :class:`int` (see :ref:`typesnumeric`).
It cannot be subclassed further. Its only instances are ``False`` and
@@ -153,14 +156,14 @@ are always available. They are listed here in alphabetical order.
.. index:: pair: Boolean; type
.. versionchanged:: 3.7
- *x* is now a positional-only parameter.
+ The parameter is now positional-only.
.. function:: breakpoint(*args, **kws)
This function drops you into the debugger at the call site. Specifically,
it calls :func:`sys.breakpointhook`, passing ``args`` and ``kws`` straight
through. By default, ``sys.breakpointhook()`` calls
- :func:`pdb.set_trace()` expecting no arguments. In this case, it is
+ :func:`pdb.set_trace` expecting no arguments. In this case, it is
purely a convenience function so you don't have to explicitly import
:mod:`pdb` or type as much code to enter the debugger. However,
:func:`sys.breakpointhook` can be set to some other function and
@@ -182,8 +185,7 @@ are always available. They are listed here in alphabetical order.
.. _func-bytearray:
.. class:: bytearray(source=b'')
- bytearray(source, encoding)
- bytearray(source, encoding, errors)
+ bytearray(source, encoding, errors='strict')
:noindex:
Return a new array of bytes. The :class:`bytearray` class is a mutable
@@ -214,8 +216,7 @@ are always available. They are listed here in alphabetical order.
.. _func-bytes:
.. class:: bytes(source=b'')
- bytes(source, encoding)
- bytes(source, encoding, errors)
+ bytes(source, encoding, errors='strict')
:noindex:
Return a new "bytes" object which is an immutable sequence of integers in
@@ -230,7 +231,7 @@ are always available. They are listed here in alphabetical order.
See also :ref:`binaryseq`, :ref:`typebytes`, and :ref:`bytes-methods`.
-.. function:: callable(object)
+.. function:: callable(object, /)
Return :const:`True` if the *object* argument appears callable,
:const:`False` if not. If this returns ``True``, it is still possible that a
@@ -243,14 +244,14 @@ are always available. They are listed here in alphabetical order.
in Python 3.2.
-.. function:: chr(i)
+.. function:: chr(codepoint, /)
- Return the string representing a character whose Unicode code point is the
- integer *i*. For example, ``chr(97)`` returns the string ``'a'``, while
+ Return the string representing a character with the specified Unicode code point.
+ For example, ``chr(97)`` returns the string ``'a'``, while
``chr(8364)`` returns the string ``'€'``. This is the inverse of :func:`ord`.
The valid range for the argument is from 0 through 1,114,111 (0x10FFFF in
- base 16). :exc:`ValueError` will be raised if *i* is outside that range.
+ base 16). :exc:`ValueError` will be raised if it is outside that range.
.. decorator:: classmethod
@@ -282,9 +283,11 @@ are always available. They are listed here in alphabetical order.
:func:`property`.
.. versionchanged:: 3.10
- Class methods now inherit the method attributes (``__module__``,
- ``__name__``, ``__qualname__``, ``__doc__`` and ``__annotations__``) and
- have a new ``__wrapped__`` attribute.
+ Class methods now inherit the method attributes
+ (:attr:`~function.__module__`, :attr:`~function.__name__`,
+ :attr:`~function.__qualname__`, :attr:`~function.__doc__` and
+ :attr:`~function.__annotations__`) and have a new ``__wrapped__``
+ attribute.
.. deprecated-removed:: 3.11 3.13
Class methods can no longer wrap other :term:`descriptors ` such as
@@ -333,8 +336,8 @@ are always available. They are listed here in alphabetical order.
``__debug__`` is true), ``1`` (asserts are removed, ``__debug__`` is false)
or ``2`` (docstrings are removed too).
- This function raises :exc:`SyntaxError` if the compiled source is invalid,
- and :exc:`ValueError` if the source contains null bytes.
+ This function raises :exc:`SyntaxError` or :exc:`ValueError` if the compiled
+ source is invalid.
If you want to parse Python code into its AST representation, see
:func:`ast.parse`.
@@ -371,29 +374,73 @@ are always available. They are listed here in alphabetical order.
support for top-level ``await``, ``async for``, and ``async with``.
-.. class:: complex(real=0, imag=0)
- complex(string)
+.. class:: complex(number=0, /)
+ complex(string, /)
+ complex(real=0, imag=0)
+
+ Convert a single string or number to a complex number, or create a
+ complex number from real and imaginary parts.
+
+ Examples:
+
+ .. doctest::
+
+ >>> complex('+1.23')
+ (1.23+0j)
+ >>> complex('-4.5j')
+ -4.5j
+ >>> complex('-1.23+4.5j')
+ (-1.23+4.5j)
+ >>> complex('\t( -1.23+4.5J )\n')
+ (-1.23+4.5j)
+ >>> complex('-Infinity+NaNj')
+ (-inf+nanj)
+ >>> complex(1.23)
+ (1.23+0j)
+ >>> complex(imag=-4.5)
+ -4.5j
+ >>> complex(-1.23, 4.5)
+ (-1.23+4.5j)
+
+ If the argument is a string, it must contain either a real part (in the
+ same format as for :func:`float`) or an imaginary part (in the same
+ format but with a ``'j'`` or ``'J'`` suffix), or both real and imaginary
+ parts (the sign of the imaginary part is mandatory in this case).
+ The string can optionally be surrounded by whitespaces and the round
+ parentheses ``'('`` and ``')'``, which are ignored.
+ The string must not contain whitespace between ``'+'``, ``'-'``, the
+ ``'j'`` or ``'J'`` suffix, and the decimal number.
+ For example, ``complex('1+2j')`` is fine, but ``complex('1 + 2j')`` raises
+ :exc:`ValueError`.
+ More precisely, the input must conform to the :token:`~float:complexvalue`
+ production rule in the following grammar, after parentheses and leading and
+ trailing whitespace characters are removed:
- Return a complex number with the value *real* + *imag*\*1j or convert a string
- or number to a complex number. If the first parameter is a string, it will
- be interpreted as a complex number and the function must be called without a
- second parameter. The second parameter can never be a string. Each argument
- may be any numeric type (including complex). If *imag* is omitted, it
- defaults to zero and the constructor serves as a numeric conversion like
- :class:`int` and :class:`float`. If both arguments are omitted, returns
- ``0j``.
+ .. productionlist:: float
+ complexvalue: `floatvalue` |
+ : `floatvalue` ("j" | "J") |
+ : `floatvalue` `sign` `absfloatvalue` ("j" | "J")
+ If the argument is a number, the constructor serves as a numeric
+ conversion like :class:`int` and :class:`float`.
For a general Python object ``x``, ``complex(x)`` delegates to
- ``x.__complex__()``. If :meth:`~object.__complex__` is not defined then it falls back
- to :meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back
+ ``x.__complex__()``.
+ If :meth:`~object.__complex__` is not defined then it falls back
+ to :meth:`~object.__float__`.
+ If :meth:`!__float__` is not defined then it falls back
to :meth:`~object.__index__`.
- .. note::
+ If two arguments are provided or keyword arguments are used, each argument
+ may be any numeric type (including complex).
+ If both arguments are real numbers, return a complex number with the real
+ component *real* and the imaginary component *imag*.
+ If both arguments are complex numbers, return a complex number with the real
+ component ``real.real-imag.imag`` and the imaginary component
+ ``real.imag+imag.real``.
+ If one of arguments is a real number, only its real component is used in
+ the above expressions.
- When converting from a string, the string must not contain whitespace
- around the central ``+`` or ``-`` operator. For example,
- ``complex('1+2j')`` is fine, but ``complex('1 + 2j')`` raises
- :exc:`ValueError`.
+ If all arguments are omitted, returns ``0j``.
The complex type is described in :ref:`typesnumeric`.
@@ -405,7 +452,7 @@ are always available. They are listed here in alphabetical order.
:meth:`~object.__float__` are not defined.
-.. function:: delattr(object, name)
+.. function:: delattr(object, name, /)
This is a relative of :func:`setattr`. The arguments are an object and a
string. The string must be the name of one of the object's attributes. The
@@ -415,20 +462,20 @@ are always available. They are listed here in alphabetical order.
.. _func-dict:
-.. class:: dict(**kwarg)
- dict(mapping, **kwarg)
- dict(iterable, **kwarg)
+.. class:: dict(**kwargs)
+ dict(mapping, /, **kwargs)
+ dict(iterable, /, **kwargs)
:noindex:
Create a new dictionary. The :class:`dict` object is the dictionary class.
- See :class:`dict` and :ref:`typesmapping` for documentation about this class.
+ See also :ref:`typesmapping` for documentation about this class.
For other containers see the built-in :class:`list`, :class:`set`, and
:class:`tuple` classes, as well as the :mod:`collections` module.
.. function:: dir()
- dir(object)
+ dir(object, /)
Without arguments, return the list of names in the current local scope. With an
argument, attempt to return a list of valid attributes for that object.
@@ -488,12 +535,12 @@ are always available. They are listed here in alphabetical order.
class.
-.. function:: divmod(a, b)
+.. function:: divmod(a, b, /)
Take two (non-complex) numbers as arguments and return a pair of numbers
consisting of their quotient and remainder when using integer division. With
mixed operand types, the rules for binary arithmetic operators apply. For
- integers, the result is the same as ``(a // b, a % b)``. For floating point
+ integers, the result is the same as ``(a // b, a % b)``. For floating-point
numbers the result is ``(q, a % b)``, where *q* is usually ``math.floor(a /
b)`` but may be 1 less than that. In any case ``q * b + a % b`` is very
close to *a*, if ``a % b`` is non-zero it has the same sign as *b*, and ``0
@@ -541,20 +588,28 @@ are always available. They are listed here in alphabetical order.
:returns: The result of the evaluated expression.
:raises: Syntax errors are reported as exceptions.
- The *expression* argument is parsed and evaluated as a Python expression
- (technically speaking, a condition list) using the *globals* and *locals*
- dictionaries as global and local namespace. If the *globals* dictionary is
- present and does not contain a value for the key ``__builtins__``, a
+ .. warning::
+
+ This function executes arbitrary code. Calling it with
+ untrusted user-supplied input will lead to security vulnerabilities.
+
+ The *source* argument is parsed and evaluated as a Python expression
+ (technically speaking, an :ref:`expression list `)
+ using the *globals* and *locals* mappings as global and local namespace.
+ If the *globals* dictionary is present and does not contain a value for the
+ key ``__builtins__``, a
reference to the dictionary of the built-in module :mod:`builtins` is
- inserted under that key before *expression* is parsed. That way you can
- control what builtins are available to the executed code by inserting your
- own ``__builtins__`` dictionary into *globals* before passing it to
- :func:`eval`. If the *locals* dictionary is omitted it defaults to the
- *globals* dictionary. If both dictionaries are omitted, the expression is
+ inserted under that key before *source* is parsed.
+ Overriding ``__builtins__`` can be used to restrict or change the available
+ names, but this is **not** a security mechanism: the executed code can
+ still access all builtins.
+ If the *locals* mapping is omitted it defaults to the
+ *globals* dictionary. If both mappings are omitted, the source is
executed with the *globals* and *locals* in the environment where
- :func:`eval` is called. Note, *eval()* does not have access to the
+ :func:`eval` is called. Note, *eval()* will only have access to the
:term:`nested scopes ` (non-locals) in the enclosing
- environment.
+ environment if they are already referenced in the scope that is calling
+ :func:`eval` (e.g. via a :keyword:`nonlocal` statement).
Example:
@@ -562,6 +617,9 @@ are always available. They are listed here in alphabetical order.
>>> eval('x+1')
2
+ >>> eval("1, 2")
+ (1, 2)
+
This function can also be used to execute arbitrary code objects (such as
those created by :func:`compile`). In this case, pass a code object instead
of a string. If the code object has been compiled with ``'exec'`` as the
@@ -575,7 +633,7 @@ are always available. They are listed here in alphabetical order.
If the given source is a string, then leading and trailing spaces and tabs
are stripped.
- See :func:`ast.literal_eval` for a function that can safely evaluate strings
+ See :func:`ast.literal_eval` for a function to evaluate strings
with expressions containing only literals.
.. audit-event:: exec code_object eval
@@ -587,10 +645,20 @@ are always available. They are listed here in alphabetical order.
The *globals* and *locals* arguments can now be passed as keywords.
+ .. versionchanged:: 3.13
+
+ The semantics of the default *locals* namespace have been adjusted as
+ described for the :func:`locals` builtin.
+
.. index:: pair: built-in function; exec
.. function:: exec(source, /, globals=None, locals=None, *, closure=None)
+ .. warning::
+
+ This function executes arbitrary code. Calling it with
+ untrusted user-supplied input will lead to security vulnerabilities.
+
This function supports dynamic execution of Python code. *source* must be
either a string or a code object. If it is a string, the string is parsed as
a suite of Python statements which is then executed (unless a syntax error
@@ -608,20 +676,28 @@ are always available. They are listed here in alphabetical order.
will be used for both the global and the local variables. If *globals* and
*locals* are given, they are used for the global and local variables,
respectively. If provided, *locals* can be any mapping object. Remember
- that at the module level, globals and locals are the same dictionary. If exec
- gets two separate objects as *globals* and *locals*, the code will be
- executed as if it were embedded in a class definition.
+ that at the module level, globals and locals are the same dictionary.
+
+ .. note::
+
+ When ``exec`` gets two separate objects as *globals* and *locals*, the
+ code will be executed as if it were embedded in a class definition. This
+ means functions and classes defined in the executed code will not be able
+ to access variables assigned at the top level (as the "top level"
+ variables are treated as class variables in a class definition).
If the *globals* dictionary does not contain a value for the key
``__builtins__``, a reference to the dictionary of the built-in module
- :mod:`builtins` is inserted under that key. That way you can control what
- builtins are available to the executed code by inserting your own
- ``__builtins__`` dictionary into *globals* before passing it to :func:`exec`.
+ :mod:`builtins` is inserted under that key.
+ Overriding ``__builtins__`` can be used to restrict or change the available
+ names, but this is **not** a security mechanism: the executed code can
+ still access all builtins.
The *closure* argument specifies a closure--a tuple of cellvars.
- It's only valid when the *object* is a code object containing free variables.
- The length of the tuple must exactly match the number of free variables
- referenced by the code object.
+ It's only valid when the *object* is a code object containing
+ :term:`free (closure) variables `.
+ The length of the tuple must exactly match the length of the code object's
+ :attr:`~codeobject.co_freevars` attribute.
.. audit-event:: exec code_object exec
@@ -631,7 +707,7 @@ are always available. They are listed here in alphabetical order.
.. note::
The built-in functions :func:`globals` and :func:`locals` return the current
- global and local dictionary, respectively, which may be useful to pass around
+ global and local namespace, respectively, which may be useful to pass around
for use as the second and third argument to :func:`exec`.
.. note::
@@ -647,8 +723,13 @@ are always available. They are listed here in alphabetical order.
The *globals* and *locals* arguments can now be passed as keywords.
+ .. versionchanged:: 3.13
+
+ The semantics of the default *locals* namespace have been adjusted as
+ described for the :func:`locals` builtin.
+
-.. function:: filter(function, iterable)
+.. function:: filter(function, iterable, /)
Construct an iterator from those elements of *iterable* for which *function*
is true. *iterable* may be either a sequence, a container which
@@ -665,21 +746,38 @@ are always available. They are listed here in alphabetical order.
elements of *iterable* for which *function* is false.
-.. class:: float(x=0.0)
+.. class:: float(number=0.0, /)
+ float(string, /)
.. index::
single: NaN
single: Infinity
- Return a floating point number constructed from a number or string *x*.
+ Return a floating-point number constructed from a number or a string.
+
+ Examples:
+
+ .. doctest::
+
+ >>> float('+1.23')
+ 1.23
+ >>> float(' -12345\n')
+ -12345.0
+ >>> float('1e-003')
+ 0.001
+ >>> float('+1E6')
+ 1000000.0
+ >>> float('-Infinity')
+ -inf
If the argument is a string, it should contain a decimal number, optionally
preceded by a sign, and optionally embedded in whitespace. The optional
sign may be ``'+'`` or ``'-'``; a ``'+'`` sign has no effect on the value
produced. The argument may also be a string representing a NaN
- (not-a-number), or positive or negative infinity. More precisely, the
- input must conform to the ``floatvalue`` production rule in the following
- grammar, after leading and trailing whitespace characters are removed:
+ (not-a-number), or positive or negative infinity.
+ More precisely, the input must conform to the :token:`~float:floatvalue`
+ production rule in the following grammar, after leading and trailing
+ whitespace characters are removed:
.. productionlist:: float
sign: "+" | "-"
@@ -688,15 +786,16 @@ are always available. They are listed here in alphabetical order.
digit:
digitpart: `digit` (["_"] `digit`)*
number: [`digitpart`] "." `digitpart` | `digitpart` ["."]
- exponent: ("e" | "E") ["+" | "-"] `digitpart`
- floatnumber: number [`exponent`]
- floatvalue: [`sign`] (`floatnumber` | `infinity` | `nan`)
+ exponent: ("e" | "E") [`sign`] `digitpart`
+ floatnumber: `number` [`exponent`]
+ absfloatvalue: `floatnumber` | `infinity` | `nan`
+ floatvalue: [`sign`] `absfloatvalue`
Case is not significant, so, for example, "inf", "Inf", "INFINITY", and
"iNfINity" are all acceptable spellings for positive infinity.
- Otherwise, if the argument is an integer or a floating point number, a
- floating point number with the same value (within Python's floating point
+ Otherwise, if the argument is an integer or a floating-point number, a
+ floating-point number with the same value (within Python's floating-point
precision) is returned. If the argument is outside the range of a Python
float, an :exc:`OverflowError` will be raised.
@@ -706,26 +805,13 @@ are always available. They are listed here in alphabetical order.
If no argument is given, ``0.0`` is returned.
- Examples::
-
- >>> float('+1.23')
- 1.23
- >>> float(' -12345\n')
- -12345.0
- >>> float('1e-003')
- 0.001
- >>> float('+1E6')
- 1000000.0
- >>> float('-Infinity')
- -inf
-
The float type is described in :ref:`typesnumeric`.
.. versionchanged:: 3.6
Grouping digits with underscores as in code literals is allowed.
.. versionchanged:: 3.7
- *x* is now a positional-only parameter.
+ The parameter is now positional-only.
.. versionchanged:: 3.8
Falls back to :meth:`~object.__index__` if :meth:`~object.__float__` is not defined.
@@ -735,7 +821,7 @@ are always available. They are listed here in alphabetical order.
single: __format__
single: string; format() (built-in function)
-.. function:: format(value, format_spec="")
+.. function:: format(value, format_spec="", /)
Convert a *value* to a "formatted" representation, as controlled by
*format_spec*. The interpretation of *format_spec* will depend on the type
@@ -758,11 +844,11 @@ are always available. They are listed here in alphabetical order.
.. _func-frozenset:
-.. class:: frozenset(iterable=set())
+.. class:: frozenset(iterable=(), /)
:noindex:
Return a new :class:`frozenset` object, optionally with elements taken from
- *iterable*. ``frozenset`` is a built-in class. See :class:`frozenset` and
+ *iterable*. :class:`frozenset` is a built-in class. See also
:ref:`types-set` for documentation about this class.
For other containers see the built-in :class:`set`, :class:`list`,
@@ -770,8 +856,8 @@ are always available. They are listed here in alphabetical order.
module.
-.. function:: getattr(object, name)
- getattr(object, name, default)
+.. function:: getattr(object, name, /)
+ getattr(object, name, default, /)
Return the value of the named attribute of *object*. *name* must be a string.
If the string is the name of one of the object's attributes, the result is the
@@ -795,7 +881,7 @@ are always available. They are listed here in alphabetical order.
regardless of where the function is called.
-.. function:: hasattr(object, name)
+.. function:: hasattr(object, name, /)
The arguments are an object and a string. The result is ``True`` if the
string is the name of one of the object's attributes, ``False`` if not. (This
@@ -803,7 +889,7 @@ are always available. They are listed here in alphabetical order.
raises an :exc:`AttributeError` or not.)
-.. function:: hash(object)
+.. function:: hash(object, /)
Return the hash value of the object (if it has one). Hash values are
integers. They are used to quickly compare dictionary keys during a
@@ -838,10 +924,10 @@ are always available. They are listed here in alphabetical order.
signatures for callables are now more comprehensive and consistent.
-.. function:: hex(x)
+.. function:: hex(integer, /)
Convert an integer number to a lowercase hexadecimal string prefixed with
- "0x". If *x* is not a Python :class:`int` object, it has to define an
+ "0x". If *integer* is not a Python :class:`int` object, it has to define an
:meth:`~object.__index__` method that returns an integer. Some examples:
>>> hex(255)
@@ -870,7 +956,7 @@ are always available. They are listed here in alphabetical order.
:meth:`float.hex` method.
-.. function:: id(object)
+.. function:: id(object, /)
Return the "identity" of an object. This is an integer which
is guaranteed to be unique and constant for this object during its lifetime.
@@ -883,7 +969,7 @@ are always available. They are listed here in alphabetical order.
.. function:: input()
- input(prompt)
+ input(prompt, /)
If the *prompt* argument is present, it is written to standard output without
a trailing newline. The function then reads a line from input, converts it
@@ -909,17 +995,36 @@ are always available. They are listed here in alphabetical order.
with the result after successfully reading input.
-.. class:: int(x=0)
- int(x, base=10)
+.. class:: int(number=0, /)
+ int(string, /, base=10)
+
+ Return an integer object constructed from a number or a string, or return
+ ``0`` if no arguments are given.
+
+ Examples:
+
+ .. doctest::
- Return an integer object constructed from a number or string *x*, or return
- ``0`` if no arguments are given. If *x* defines :meth:`~object.__int__`,
- ``int(x)`` returns ``x.__int__()``. If *x* defines :meth:`~object.__index__`,
- it returns ``x.__index__()``. If *x* defines :meth:`~object.__trunc__`,
+ >>> int(123.45)
+ 123
+ >>> int('123')
+ 123
+ >>> int(' -12_345\n')
+ -12345
+ >>> int('FACE', 16)
+ 64206
+ >>> int('0xface', 0)
+ 64206
+ >>> int('01110011', base=2)
+ 115
+
+ If the argument defines :meth:`~object.__int__`,
+ ``int(x)`` returns ``x.__int__()``. If the argument defines :meth:`~object.__index__`,
+ it returns ``x.__index__()``. If the argument defines :meth:`~object.__trunc__`,
it returns ``x.__trunc__()``.
- For floating point numbers, this truncates towards zero.
+ For floating-point numbers, this truncates towards zero.
- If *x* is not a number or if *base* is given, then *x* must be a string,
+ If the argument is not a number or if *base* is given, then it must be a string,
:class:`bytes`, or :class:`bytearray` instance representing an integer
in radix *base*. Optionally, the string can be preceded by ``+`` or ``-``
(with no space in between), have leading zeros, be surrounded by whitespace,
@@ -949,7 +1054,7 @@ are always available. They are listed here in alphabetical order.
Grouping digits with underscores as in code literals is allowed.
.. versionchanged:: 3.7
- *x* is now a positional-only parameter.
+ The first parameter is now positional-only.
.. versionchanged:: 3.8
Falls back to :meth:`~object.__index__` if :meth:`~object.__int__` is not defined.
@@ -960,12 +1065,13 @@ are always available. They are listed here in alphabetical order.
.. versionchanged:: 3.11
:class:`int` string inputs and string representations can be limited to
help avoid denial of service attacks. A :exc:`ValueError` is raised when
- the limit is exceeded while converting a string *x* to an :class:`int` or
+ the limit is exceeded while converting a string to an :class:`int` or
when converting an :class:`int` into a string would exceed the limit.
See the :ref:`integer string conversion length limitation
` documentation.
-.. function:: isinstance(object, classinfo)
+
+.. function:: isinstance(object, classinfo, /)
Return ``True`` if the *object* argument is an instance of the *classinfo*
argument, or of a (direct, indirect, or :term:`virtual `) of *classinfo*. A
@@ -996,19 +1102,19 @@ are always available. They are listed here in alphabetical order.
*classinfo* can be a :ref:`types-union`.
-.. function:: iter(object)
- iter(object, sentinel)
+.. function:: iter(iterable, /)
+ iter(callable, sentinel, /)
Return an :term:`iterator` object. The first argument is interpreted very
differently depending on the presence of the second argument. Without a
- second argument, *object* must be a collection object which supports the
+ second argument, the single argument must be a collection object which supports the
:term:`iterable` protocol (the :meth:`~object.__iter__` method),
or it must support
the sequence protocol (the :meth:`~object.__getitem__` method with integer arguments
starting at ``0``). If it does not support either of those protocols,
:exc:`TypeError` is raised. If the second argument, *sentinel*, is given,
- then *object* must be a callable object. The iterator created in this case
- will call *object* with no arguments for each call to its
+ then the first argument must be a callable object. The iterator created in this case
+ will call *callable* with no arguments for each call to its
:meth:`~iterator.__next__` method; if the value returned is equal to
*sentinel*, :exc:`StopIteration` will be raised, otherwise the value will
be returned.
@@ -1025,7 +1131,7 @@ are always available. They are listed here in alphabetical order.
process_block(block)
-.. function:: len(s)
+.. function:: len(object, /)
Return the length (the number of items) of an object. The argument may be a
sequence (such as a string, bytes, tuple, list, or range) or a collection
@@ -1038,8 +1144,7 @@ are always available. They are listed here in alphabetical order.
.. _func-list:
-.. class:: list()
- list(iterable)
+.. class:: list(iterable=(), /)
:noindex:
Rather than being a function, :class:`list` is actually a mutable
@@ -1048,43 +1153,55 @@ are always available. They are listed here in alphabetical order.
.. function:: locals()
- Return a mapping object representing the current local symbol table, with
- variable names as the keys, and their currently bound references as the
- values.
-
- At module scope, as well as when using ``exec()`` or ``eval()`` with a
- single namespace, this function returns the same namespace as ``globals()``.
-
- At class scope, it returns the namespace that will be passed to the
- metaclass constructor.
+ Return a mapping object representing the current local symbol table, with
+ variable names as the keys, and their currently bound references as the
+ values.
+
+ At module scope, as well as when using :func:`exec` or :func:`eval` with
+ a single namespace, this function returns the same namespace as
+ :func:`globals`.
+
+ At class scope, it returns the namespace that will be passed to the
+ metaclass constructor.
+
+ When using ``exec()`` or ``eval()`` with separate local and global
+ arguments, it returns the local namespace passed in to the function call.
+
+ In all of the above cases, each call to ``locals()`` in a given frame of
+ execution will return the *same* mapping object. Changes made through
+ the mapping object returned from ``locals()`` will be visible as assigned,
+ reassigned, or deleted local variables, and assigning, reassigning, or
+ deleting local variables will immediately affect the contents of the
+ returned mapping object.
+
+ In an :term:`optimized scope` (including functions, generators, and
+ coroutines), each call to ``locals()`` instead returns a fresh dictionary
+ containing the current bindings of the function's local variables and any
+ nonlocal cell references. In this case, name binding changes made via the
+ returned dict are *not* written back to the corresponding local variables
+ or nonlocal cell references, and assigning, reassigning, or deleting local
+ variables and nonlocal cell references does *not* affect the contents
+ of previously returned dictionaries.
+
+ Calling ``locals()`` as part of a comprehension in a function, generator, or
+ coroutine is equivalent to calling it in the containing scope, except that
+ the comprehension's initialised iteration variables will be included. In
+ other scopes, it behaves as if the comprehension were running as a nested
+ function.
+
+ Calling ``locals()`` as part of a generator expression is equivalent to
+ calling it in a nested generator function.
- When using ``exec()`` or ``eval()`` with separate local and global
- namespaces, it returns the local namespace passed in to the function call.
-
- In all of the above cases, each call to ``locals()`` in a given frame of
- execution will return the *same* mapping object. Changes made through
- the mapping object returned from ``locals()`` will be visible as bound,
- rebound, or deleted local variables, and binding, rebinding, or deleting
- local variables will immediately affect the contents of the returned mapping
- object.
-
- At function scope (including for generators and coroutines), each call to
- ``locals()`` instead returns a fresh dictionary containing the current
- bindings of the function's local variables and any nonlocal cell references.
- In this case, name binding changes made via the returned dict are *not*
- written back to the corresponding local variables or nonlocal cell
- references, and binding, rebinding, or deleting local variables and nonlocal
- cell references does *not* affect the contents of previously returned
- dictionaries.
+ .. versionchanged:: 3.12
+ The behaviour of ``locals()`` in a comprehension has been updated as
+ described in :pep:`709`.
.. versionchanged:: 3.13
- In previous versions, the semantics of mutating the mapping object
- returned from this function were formally undefined. In CPython
- specifically, the mapping returned at function scope could be
- implicitly refreshed by other operations, such as calling ``locals()``
- again. Obtaining the legacy CPython behaviour now requires explicit
- calls to update the initially returned dictionary with the results
- of subsequent calls to ``locals()``.
+ As part of :pep:`667`, the semantics of mutating the mapping objects
+ returned from this function are now defined. The behavior in
+ :term:`optimized scopes ` is now as described above.
+ Aside from being defined, the behaviour in other scopes remains
+ unchanged from previous versions.
.. function:: map(function, iterable, *iterables)
@@ -1097,9 +1214,9 @@ are always available. They are listed here in alphabetical order.
already arranged into argument tuples, see :func:`itertools.starmap`\.
-.. function:: max(iterable, *, key=None)
- max(iterable, *, default, key=None)
- max(arg1, arg2, *args, key=None)
+.. function:: max(iterable, /, *, key=None)
+ max(iterable, /, *, default, key=None)
+ max(arg1, arg2, /, *args, key=None)
Return the largest item in an iterable or the largest of two or more
arguments.
@@ -1135,9 +1252,9 @@ are always available. They are listed here in alphabetical order.
:ref:`typememoryview` for more information.
-.. function:: min(iterable, *, key=None)
- min(iterable, *, default, key=None)
- min(arg1, arg2, *args, key=None)
+.. function:: min(iterable, /, *, key=None)
+ min(iterable, /, *, default, key=None)
+ min(arg1, arg2, /, *args, key=None)
Return the smallest item in an iterable or the smallest of two or more
arguments.
@@ -1165,8 +1282,8 @@ are always available. They are listed here in alphabetical order.
The *key* can be ``None``.
-.. function:: next(iterator)
- next(iterator, default)
+.. function:: next(iterator, /)
+ next(iterator, default, /)
Retrieve the next item from the :term:`iterator` by calling its
:meth:`~iterator.__next__` method. If *default* is given, it is returned
@@ -1175,20 +1292,22 @@ are always available. They are listed here in alphabetical order.
.. class:: object()
- Return a new featureless object. :class:`object` is a base for all classes.
- It has methods that are common to all instances of Python classes. This
- function does not accept any arguments.
+ This is the ultimate base class of all other classes. It has methods
+ that are common to all instances of Python classes. When the constructor
+ is called, it returns a new featureless object. The constructor does not
+ accept any arguments.
.. note::
- :class:`object` does *not* have a :attr:`~object.__dict__`, so you can't
- assign arbitrary attributes to an instance of the :class:`object` class.
+ :class:`object` instances do *not* have :attr:`~object.__dict__`
+ attributes, so you can't assign arbitrary attributes to an instance of
+ :class:`object`.
-.. function:: oct(x)
+.. function:: oct(integer, /)
Convert an integer number to an octal string prefixed with "0o". The result
- is a valid Python expression. If *x* is not a Python :class:`int` object, it
+ is a valid Python expression. If *integer* is not a Python :class:`int` object, it
has to define an :meth:`~object.__index__` method that returns an integer. For
example:
@@ -1231,7 +1350,7 @@ are always available. They are listed here in alphabetical order.
(which on *some* Unix systems, means that *all* writes append to the end of
the file regardless of the current seek position). In text mode, if
*encoding* is not specified the encoding used is platform-dependent:
- :func:`locale.getencoding()` is called to get the current locale encoding.
+ :func:`locale.getencoding` is called to get the current locale encoding.
(For reading and writing raw bytes use binary mode and leave
*encoding* unspecified.) The available modes are:
@@ -1404,7 +1523,7 @@ are always available. They are listed here in alphabetical order.
(where :func:`open` is declared), :mod:`os`, :mod:`os.path`, :mod:`tempfile`,
and :mod:`shutil`.
- .. audit-event:: open file,mode,flags open
+ .. audit-event:: open path,mode,flags open
The ``mode`` and ``flags`` arguments may have been modified or inferred from
the original call.
@@ -1437,13 +1556,19 @@ are always available. They are listed here in alphabetical order.
.. versionchanged:: 3.11
The ``'U'`` mode has been removed.
-.. function:: ord(c)
+.. function:: ord(character, /)
- Given a string representing one Unicode character, return an integer
- representing the Unicode code point of that character. For example,
+ Return the ordinal value of a character.
+
+ If the argument is a one-character string, return the Unicode code point
+ of that character. For example,
``ord('a')`` returns the integer ``97`` and ``ord('€')`` (Euro sign)
returns ``8364``. This is the inverse of :func:`chr`.
+ If the argument is a :class:`bytes` or :class:`bytearray` object of
+ length 1, return its single byte value.
+ For example, ``ord(b'a')`` returns the integer ``97``.
+
.. function:: pow(base, exp, mod=None)
@@ -1452,7 +1577,7 @@ are always available. They are listed here in alphabetical order.
``pow(base, exp) % mod``). The two-argument form ``pow(base, exp)`` is
equivalent to using the power operator: ``base**exp``.
- The arguments must have numeric types. With mixed operand types, the
+ When arguments are builtin numeric types with mixed operand types, the
coercion rules for binary arithmetic operators apply. For :class:`int`
operands, the result has the same type as the operands (after coercion)
unless the second argument is negative; in that case, all arguments are
@@ -1460,7 +1585,9 @@ are always available. They are listed here in alphabetical order.
returns ``100``, but ``pow(10, -2)`` returns ``0.01``. For a negative base of
type :class:`int` or :class:`float` and a non-integral exponent, a complex
result is delivered. For example, ``pow(-9, 0.5)`` returns a value close
- to ``3j``.
+ to ``3j``. Whereas, for a negative base of type :class:`int` or :class:`float`
+ with an integral exponent, a float result is delivered. For example,
+ ``pow(-9, 2.0)`` returns ``81.0``.
For :class:`int` operands *base* and *exp*, if *mod* is present, *mod* must
also be of integer type and *mod* must be nonzero. If *mod* is present and
@@ -1540,7 +1667,7 @@ are always available. They are listed here in alphabetical order.
If given, *doc* will be the docstring of the property attribute. Otherwise, the
property will copy *fget*'s docstring (if it exists). This makes it possible to
- create read-only properties easily using :func:`property` as a :term:`decorator`::
+ create read-only properties easily using :deco:`property` as a :term:`decorator`::
class Parrot:
def __init__(self):
@@ -1593,17 +1720,24 @@ are always available. They are listed here in alphabetical order.
.. versionchanged:: 3.5
The docstrings of property objects are now writeable.
+ .. attribute:: __name__
+
+ Attribute holding the name of the property. The name of the property
+ can be changed at runtime.
+
+ .. versionadded:: 3.13
+
.. _func-range:
-.. class:: range(stop)
- range(start, stop, step=1)
+.. class:: range(stop, /)
+ range(start, stop, step=1, /)
:noindex:
Rather than being a function, :class:`range` is actually an immutable
sequence type, as documented in :ref:`typesseq-range` and :ref:`typesseq`.
-.. function:: repr(object)
+.. function:: repr(object, /)
Return a string containing a printable representation of an object. For many
types, this function makes an attempt to return a string that would yield an
@@ -1627,9 +1761,9 @@ are always available. They are listed here in alphabetical order.
return f"Person('{self.name}', {self.age})"
-.. function:: reversed(seq)
+.. function:: reversed(object, /)
- Return a reverse :term:`iterator`. *seq* must be an object which has
+ Return a reverse :term:`iterator`. The argument must be an object which has
a :meth:`~object.__reversed__` method or supports the sequence protocol (the
:meth:`~object.__len__` method and the :meth:`~object.__getitem__` method
with integer arguments starting at ``0``).
@@ -1663,12 +1797,11 @@ are always available. They are listed here in alphabetical order.
.. _func-set:
-.. class:: set()
- set(iterable)
+.. class:: set(iterable=(), /)
:noindex:
Return a new :class:`set` object, optionally with elements taken from
- *iterable*. ``set`` is a built-in class. See :class:`set` and
+ *iterable*. :class:`set` is a built-in class. See also
:ref:`types-set` for documentation about this class.
For other containers see the built-in :class:`frozenset`, :class:`list`,
@@ -1676,7 +1809,7 @@ are always available. They are listed here in alphabetical order.
module.
-.. function:: setattr(object, name, value)
+.. function:: setattr(object, name, value, /)
This is the counterpart of :func:`getattr`. The arguments are an object, a
string, and an arbitrary value. The string may name an existing attribute or a
@@ -1698,22 +1831,22 @@ are always available. They are listed here in alphabetical order.
:func:`setattr`.
-.. class:: slice(stop)
- slice(start, stop, step=None)
+.. class:: slice(stop, /)
+ slice(start, stop, step=None, /)
Return a :term:`slice` object representing the set of indices specified by
``range(start, stop, step)``. The *start* and *step* arguments default to
``None``.
+ Slice objects have read-only data attributes :attr:`!start`,
+ :attr:`!stop`, and :attr:`!step` which merely return the argument
+ values (or their default). They have no other explicit functionality;
+ however, they are used by NumPy and other third-party packages.
+
.. attribute:: slice.start
.. attribute:: slice.stop
.. attribute:: slice.step
- Slice objects have read-only data attributes :attr:`!start`,
- :attr:`!stop`, and :attr:`!step` which merely return the argument
- values (or their default). They have no other explicit functionality;
- however, they are used by NumPy and other third-party packages.
-
Slice objects are also generated when extended indexing syntax is used. For
example: ``a[start:stop:step]`` or ``a[start:stop, i]``. See
:func:`itertools.islice` for an alternate version that returns an
@@ -1751,7 +1884,7 @@ are always available. They are listed here in alphabetical order.
the same data with other ordering tools such as :func:`max` that rely
on a different underlying method. Implementing all six comparisons
also helps avoid confusion for mixed type comparisons which can call
- reflected the :meth:`~object.__gt__` method.
+ the reflected :meth:`~object.__gt__` method.
For sorting examples and a brief sorting tutorial, see :ref:`sortinghowto`.
@@ -1775,7 +1908,7 @@ are always available. They are listed here in alphabetical order.
be used in the class definition (such as ``f()``).
Static methods in Python are similar to those found in Java or C++. Also, see
- :func:`classmethod` for a variant that is useful for creating alternate class
+ :deco:`classmethod` for a variant that is useful for creating alternate class
constructors.
Like all decorators, it is also possible to call ``staticmethod`` as
@@ -1793,18 +1926,21 @@ are always available. They are listed here in alphabetical order.
For more information on static methods, see :ref:`types`.
.. versionchanged:: 3.10
- Static methods now inherit the method attributes (``__module__``,
- ``__name__``, ``__qualname__``, ``__doc__`` and ``__annotations__``),
- have a new ``__wrapped__`` attribute, and are now callable as regular
- functions.
+ Static methods now inherit the method attributes
+ (:attr:`~function.__module__`, :attr:`~function.__name__`,
+ :attr:`~function.__qualname__`, :attr:`~function.__doc__` and
+ :attr:`~function.__annotations__`), have a new ``__wrapped__`` attribute,
+ and are now callable as regular functions.
.. index::
single: string; str() (built-in function)
.. _func-str:
-.. class:: str(object='')
- str(object=b'', encoding='utf-8', errors='strict')
+.. class:: str(*, encoding='utf-8', errors='strict')
+ str(object)
+ str(object, encoding, errors='strict')
+ str(object, *, errors)
:noindex:
Return a :class:`str` version of *object*. See :func:`str` for details.
@@ -1821,7 +1957,7 @@ are always available. They are listed here in alphabetical order.
For some use cases, there are good alternatives to :func:`sum`.
The preferred, fast way to concatenate a sequence of strings is by calling
- ``''.join(sequence)``. To add floating point values with extended precision,
+ ``''.join(sequence)``. To add floating-point values with extended precision,
see :func:`math.fsum`\. To concatenate a series of iterables, consider using
:func:`itertools.chain`.
@@ -1833,7 +1969,7 @@ are always available. They are listed here in alphabetical order.
.. class:: super()
- super(type, object_or_type=None)
+ super(type, object_or_type=None, /)
Return a proxy object that delegates method calls to a parent or sibling
class of *type*. This is useful for accessing inherited methods that have
@@ -1843,14 +1979,14 @@ are always available. They are listed here in alphabetical order.
to be searched. The search starts from the class right after the
*type*.
- For example, if :attr:`~class.__mro__` of *object_or_type* is
+ For example, if :attr:`~type.__mro__` of *object_or_type* is
``D -> B -> C -> A -> object`` and the value of *type* is ``B``,
then :func:`super` searches ``C -> A -> object``.
- The :attr:`~class.__mro__` attribute of the *object_or_type* lists the method
- resolution search order used by both :func:`getattr` and :func:`super`. The
- attribute is dynamic and can change whenever the inheritance hierarchy is
- updated.
+ The :attr:`~type.__mro__` attribute of the class corresponding to
+ *object_or_type* lists the method resolution search order used by both
+ :func:`getattr` and :func:`super`. The attribute is dynamic and can change
+ whenever the inheritance hierarchy is updated.
If the second argument is omitted, the super object returned is unbound. If
the second argument is an object, ``isinstance(obj, type)`` must be true. If
@@ -1911,74 +2047,84 @@ are always available. They are listed here in alphabetical order.
.. _func-tuple:
-.. class:: tuple()
- tuple(iterable)
+.. class:: tuple(iterable=(), /)
:noindex:
Rather than being a function, :class:`tuple` is actually an immutable
sequence type, as documented in :ref:`typesseq-tuple` and :ref:`typesseq`.
-.. class:: type(object)
- type(name, bases, dict, **kwds)
+.. class:: type(object, /)
+ type(name, bases, dict, /, **kwargs)
.. index:: pair: object; type
With one argument, return the type of an *object*. The return value is a
type object and generally the same object as returned by
- :attr:`object.__class__ `.
+ :attr:`object.__class__`.
The :func:`isinstance` built-in function is recommended for testing the type
of an object, because it takes subclasses into account.
-
With three arguments, return a new type object. This is essentially a
dynamic form of the :keyword:`class` statement. The *name* string is
- the class name and becomes the :attr:`~definition.__name__` attribute.
+ the class name and becomes the :attr:`~type.__name__` attribute.
The *bases* tuple contains the base classes and becomes the
- :attr:`~class.__bases__` attribute; if empty, :class:`object`, the
+ :attr:`~type.__bases__` attribute; if empty, :class:`object`, the
ultimate base of all classes, is added. The *dict* dictionary contains
attribute and method definitions for the class body; it may be copied
- or wrapped before becoming the :attr:`~object.__dict__` attribute.
- The following two statements create identical :class:`type` objects:
+ or wrapped before becoming the :attr:`~type.__dict__` attribute.
+ The following two statements create identical :class:`!type` objects:
>>> class X:
... a = 1
...
>>> X = type('X', (), dict(a=1))
- See also :ref:`bltin-type-objects`.
+ See also:
+
+ * :ref:`Documentation on attributes and methods on classes `.
+ * :ref:`bltin-type-objects`
Keyword arguments provided to the three argument form are passed to the
appropriate metaclass machinery (usually :meth:`~object.__init_subclass__`)
in the same way that keywords in a class
definition (besides *metaclass*) would.
+ Unlike a :keyword:`class` statement, the three argument form does not
+ call the metaclass ``__prepare__`` method (see :ref:`prepare`). Use
+ :func:`types.new_class` to dynamically create a class using the
+ appropriate metaclass.
+
See also :ref:`class-customization`.
.. versionchanged:: 3.6
- Subclasses of :class:`type` which don't override ``type.__new__`` may no
+ Subclasses of :class:`!type` which don't override ``type.__new__`` may no
longer use the one-argument form to get the type of an object.
.. function:: vars()
- vars(object)
+ vars(object, /)
Return the :attr:`~object.__dict__` attribute for a module, class, instance,
- or any other object with a :attr:`~object.__dict__` attribute.
+ or any other object with a :attr:`!__dict__` attribute.
Objects such as modules and instances have an updateable :attr:`~object.__dict__`
attribute; however, other objects may have write restrictions on their
- :attr:`~object.__dict__` attributes (for example, classes use a
+ :attr:`!__dict__` attributes (for example, classes use a
:class:`types.MappingProxyType` to prevent direct dictionary updates).
- Without an argument, :func:`vars` acts like :func:`locals`. Note, the
- locals dictionary is only useful for reads since updates to the locals
- dictionary are ignored.
+ Without an argument, :func:`vars` acts like :func:`locals`.
A :exc:`TypeError` exception is raised if an object is specified but
it doesn't have a :attr:`~object.__dict__` attribute (for example, if
its class defines the :attr:`~object.__slots__` attribute).
+ .. versionchanged:: 3.13
+
+ The result of calling this function without an argument has been
+ updated as described for the :func:`locals` builtin.
+
+
.. function:: zip(*iterables, strict=False)
Iterate over several iterables in parallel, producing tuples with an item
diff --git a/Doc/builtins/index.rst b/Doc/builtins/index.rst
new file mode 100644
index 000000000000000..0b9c0389e6e59c8
--- /dev/null
+++ b/Doc/builtins/index.rst
@@ -0,0 +1,33 @@
+.. _builtins-index:
+
+##############################
+ Python built-ins reference
+##############################
+
+Python comes with a number of built-in functions and classes.
+
+The built-in classes include data types that would normally be considered part
+of the "core" of a language, such as numbers and lists. For these types, the
+Python language core defines the form of literals and places some constraints
+on their semantics, but does not fully define the semantics.
+
+The built-ins also include functions and exceptions --- objects that can
+be used by all Python code without the need of an :keyword:`import` statement.
+Some of these are defined by the core language, but many are not essential for
+the core semantics and are only described here.
+
+.. seealso::
+
+ In addition to the built-ins, Python provides an extensive importable
+ standard library, see :ref:`library-index`.
+
+.. We don't use :numbered: option for the TOC below as it enforces
+ numbered sections for the entire builtin docs. If desired,
+ :numbered: can be enabled on a per-page basis.
+.. toctree::
+ :maxdepth: 2
+
+ stdtypes.rst
+ constants.rst
+ functions.rst
+ exceptions.rst
diff --git a/Doc/library/stdtypes.rst b/Doc/builtins/stdtypes.rst
similarity index 84%
rename from Doc/library/stdtypes.rst
rename to Doc/builtins/stdtypes.rst
index 8f5f9ee519a5739..0102d1f62ed4111 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/builtins/stdtypes.rst
@@ -164,7 +164,7 @@ This table summarizes the comparison operations:
pair: object; numeric
pair: objects; comparing
-Objects of different types, except different numeric types, never compare equal.
+Unless stated otherwise, objects of different types never compare equal.
The ``==`` operator is always defined but for some object types (for example,
class objects) is equivalent to :keyword:`is`. The ``<``, ``<=``, ``>`` and ``>=``
operators are only defined where they make sense; for example, they raise a
@@ -209,18 +209,18 @@ Numeric Types --- :class:`int`, :class:`float`, :class:`complex`
pair: object; numeric
pair: object; Boolean
pair: object; integer
- pair: object; floating point
+ pair: object; floating-point
pair: object; complex number
pair: C; language
-There are three distinct numeric types: :dfn:`integers`, :dfn:`floating
-point numbers`, and :dfn:`complex numbers`. In addition, Booleans are a
-subtype of integers. Integers have unlimited precision. Floating point
+There are three distinct numeric types: :dfn:`integers`, :dfn:`floating-point
+numbers`, and :dfn:`complex numbers`. In addition, Booleans are a
+subtype of integers. Integers have unlimited precision. Floating-point
numbers are usually implemented using :c:expr:`double` in C; information
-about the precision and internal representation of floating point
+about the precision and internal representation of floating-point
numbers for the machine on which your program is running is available
in :data:`sys.float_info`. Complex numbers have a real and imaginary
-part, which are each a floating point number. To extract these parts
+part, which are each a floating-point number. To extract these parts
from a complex number *z*, use ``z.real`` and ``z.imag``. (The standard
library includes the additional numeric types :mod:`fractions.Fraction`, for
rationals, and :mod:`decimal.Decimal`, for floating-point numbers with
@@ -229,7 +229,7 @@ user-definable precision.)
.. index::
pair: numeric; literals
pair: integer; literals
- pair: floating point; literals
+ pair: floating-point; literals
pair: complex number; literals
pair: hexadecimal; literals
pair: octal; literals
@@ -238,7 +238,7 @@ user-definable precision.)
Numbers are created by numeric literals or as the result of built-in functions
and operators. Unadorned integer literals (including hex, octal and binary
numbers) yield integers. Numeric literals containing a decimal point or an
-exponent sign yield floating point numbers. Appending ``'j'`` or ``'J'`` to a
+exponent sign yield floating-point numbers. Appending ``'j'`` or ``'J'`` to a
numeric literal yields an imaginary number (a complex number with a zero real
part) which you can add to an integer or float to get a complex number with real
and imaginary parts.
@@ -673,7 +673,7 @@ A hexadecimal string takes the form::
[sign] ['0x'] integer ['.' fraction] ['p' exponent]
-where the optional ``sign`` may by either ``+`` or ``-``, ``integer``
+where the optional ``sign`` may be either ``+`` or ``-``, ``integer``
and ``fraction`` are strings of hexadecimal digits, and ``exponent``
is a decimal integer with an optional leading sign. Case is not
significant, and there must be at least one hexadecimal digit in
@@ -832,7 +832,7 @@ over ``&``, ``|`` and ``^``.
.. deprecated:: 3.12
The use of the bitwise inversion operator ``~`` is deprecated and will
- raise an error in Python 3.14.
+ raise an error in Python 3.16.
:class:`bool` is a subclass of :class:`int` (see :ref:`typesnumeric`). In
many numeric contexts, ``False`` and ``True`` behave like the integers 0 and 1, respectively.
@@ -907,9 +907,9 @@ Generator Types
---------------
Python's :term:`generator`\s provide a convenient way to implement the iterator
-protocol. If a container object's :meth:`~iterator.__iter__` method is implemented as a
+protocol. If a container object's :meth:`~object.__iter__` method is implemented as a
generator, it will automatically return an iterator object (technically, a
-generator object) supplying the :meth:`!__iter__` and :meth:`~generator.__next__`
+generator object) supplying the :meth:`~iterator.__iter__` and :meth:`~generator.__next__`
methods.
More information about generators can be found in :ref:`the documentation for
the yield expression `.
@@ -958,8 +958,6 @@ operations have the same priority as the corresponding numeric operations. [3]_
pair: slice; operation
pair: operator; in
pair: operator; not in
- single: count() (sequence method)
- single: index() (sequence method)
+--------------------------+--------------------------------+----------+
| Operation | Result | Notes |
@@ -976,7 +974,7 @@ operations have the same priority as the corresponding numeric operations. [3]_
| ``s * n`` or | equivalent to adding *s* to | (2)(7) |
| ``n * s`` | itself *n* times | |
+--------------------------+--------------------------------+----------+
-| ``s[i]`` | *i*\ th item of *s*, origin 0 | \(3) |
+| ``s[i]`` | *i*\ th item of *s*, origin 0 | (3)(8) |
+--------------------------+--------------------------------+----------+
| ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) |
+--------------------------+--------------------------------+----------+
@@ -989,13 +987,6 @@ operations have the same priority as the corresponding numeric operations. [3]_
+--------------------------+--------------------------------+----------+
| ``max(s)`` | largest item of *s* | |
+--------------------------+--------------------------------+----------+
-| ``s.index(x[, i[, j]])`` | index of the first occurrence | \(8) |
-| | of *x* in *s* (at or after | |
-| | index *i* and before index *j*)| |
-+--------------------------+--------------------------------+----------+
-| ``s.count(x)`` | total number of occurrences of | |
-| | *x* in *s* | |
-+--------------------------+--------------------------------+----------+
Sequences of the same type also support comparisons. In particular, tuples
and lists are compared lexicographically by comparing corresponding elements.
@@ -1058,11 +1049,14 @@ Notes:
still ``0``.
(4)
- The slice of *s* from *i* to *j* is defined as the sequence of items with index
- *k* such that ``i <= k < j``. If *i* or *j* is greater than ``len(s)``, use
- ``len(s)``. If *i* is omitted or ``None``, use ``0``. If *j* is omitted or
- ``None``, use ``len(s)``. If *i* is greater than or equal to *j*, the slice is
- empty.
+ The slice of *s* from *i* to *j* is defined as the sequence of items with
+ index *k* such that ``i <= k < j``.
+
+ * If *i* is omitted or ``None``, use ``0``.
+ * If *j* is omitted or ``None``, use ``len(s)``.
+ * If *i* or *j* is less than ``-len(s)``, use ``0``.
+ * If *i* or *j* is greater than ``len(s)``, use ``len(s)``.
+ * If *i* is greater than or equal to *j*, the slice is empty.
(5)
The slice of *s* from *i* to *j* with step *k* is defined as the sequence of
@@ -1101,12 +1095,41 @@ Notes:
concatenation or repetition.
(8)
- ``index`` raises :exc:`ValueError` when *x* is not found in *s*.
- Not all implementations support passing the additional arguments *i* and *j*.
- These arguments allow efficient searching of subsections of the sequence. Passing
- the extra arguments is roughly equivalent to using ``s[i:j].index(x)``, only
- without copying any data and with the returned index being relative to
- the start of the sequence rather than the start of the slice.
+ An :exc:`IndexError` is raised if *i* is outside the sequence range.
+
+.. rubric:: Sequence Methods
+
+Sequence types also support the following methods:
+
+.. method:: list.count(value, /)
+ range.count(value, /)
+ tuple.count(value, /)
+ :no-contents-entry:
+ :no-index-entry:
+ :no-typesetting:
+.. method:: sequence.count(value, /)
+
+ Return the total number of occurrences of *value* in *sequence*.
+
+.. method:: list.index(value[, start[, stop]])
+ range.index(value[, start[, stop]])
+ tuple.index(value[, start[, stop]])
+ :no-contents-entry:
+ :no-index-entry:
+ :no-typesetting:
+.. method:: sequence.index(value[, start[, stop]])
+
+ Return the index of the first occurrence of *value* in *sequence*.
+
+ Raises :exc:`ValueError` if *value* is not found in *sequence*.
+
+ The *start* or *stop* arguments allow for efficient searching
+ of subsections of the sequence, beginning at *start* and ending at *stop*.
+ This is roughly equivalent to ``start + sequence[start:stop].index(value)``,
+ only without copying any data.
+
+ .. caution::
+ Not all sequence types support passing the *start* and *stop* arguments.
.. _typesseq-immutable:
@@ -1157,14 +1180,6 @@ accepts integers that meet the value restriction ``0 <= x <= 255``).
pair: subscript; assignment
pair: slice; assignment
pair: statement; del
- single: append() (sequence method)
- single: clear() (sequence method)
- single: copy() (sequence method)
- single: extend() (sequence method)
- single: insert() (sequence method)
- single: pop() (sequence method)
- single: remove() (sequence method)
- single: reverse() (sequence method)
+------------------------------+--------------------------------+---------------------+
| Operation | Result | Notes |
@@ -1172,11 +1187,15 @@ accepts integers that meet the value restriction ``0 <= x <= 255``).
| ``s[i] = x`` | item *i* of *s* is replaced by | |
| | *x* | |
+------------------------------+--------------------------------+---------------------+
+| ``del s[i]`` | removes item *i* of *s* | |
++------------------------------+--------------------------------+---------------------+
| ``s[i:j] = t`` | slice of *s* from *i* to *j* | |
| | is replaced by the contents of | |
| | the iterable *t* | |
+------------------------------+--------------------------------+---------------------+
-| ``del s[i:j]`` | same as ``s[i:j] = []`` | |
+| ``del s[i:j]`` | removes the elements of | |
+| | ``s[i:j]`` from the list | |
+| | (same as ``s[i:j] = []``) | |
+------------------------------+--------------------------------+---------------------+
| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` | \(1) |
| | are replaced by those of *t* | |
@@ -1184,71 +1203,120 @@ accepts integers that meet the value restriction ``0 <= x <= 255``).
| ``del s[i:j:k]`` | removes the elements of | |
| | ``s[i:j:k]`` from the list | |
+------------------------------+--------------------------------+---------------------+
-| ``s.append(x)`` | appends *x* to the end of the | |
-| | sequence (same as | |
-| | ``s[len(s):len(s)] = [x]``) | |
-+------------------------------+--------------------------------+---------------------+
-| ``s.clear()`` | removes all items from *s* | \(5) |
-| | (same as ``del s[:]``) | |
-+------------------------------+--------------------------------+---------------------+
-| ``s.copy()`` | creates a shallow copy of *s* | \(5) |
-| | (same as ``s[:]``) | |
-+------------------------------+--------------------------------+---------------------+
-| ``s.extend(t)`` or | extends *s* with the | |
-| ``s += t`` | contents of *t* (for the | |
+| ``s += t`` | extends *s* with the | |
+| | contents of *t* (for the | |
| | most part the same as | |
| | ``s[len(s):len(s)] = t``) | |
+------------------------------+--------------------------------+---------------------+
-| ``s *= n`` | updates *s* with its contents | \(6) |
+| ``s *= n`` | updates *s* with its contents | \(2) |
| | repeated *n* times | |
+------------------------------+--------------------------------+---------------------+
-| ``s.insert(i, x)`` | inserts *x* into *s* at the | |
-| | index given by *i* | |
-| | (same as ``s[i:i] = [x]``) | |
-+------------------------------+--------------------------------+---------------------+
-| ``s.pop()`` or ``s.pop(i)`` | retrieves the item at *i* and | \(2) |
-| | also removes it from *s* | |
-+------------------------------+--------------------------------+---------------------+
-| ``s.remove(x)`` | remove the first item from *s* | \(3) |
-| | where ``s[i]`` is equal to *x* | |
-+------------------------------+--------------------------------+---------------------+
-| ``s.reverse()`` | reverses the items of *s* in | \(4) |
-| | place | |
-+------------------------------+--------------------------------+---------------------+
-
Notes:
(1)
- *t* must have the same length as the slice it is replacing.
+ If *k* is not equal to ``1``, *t* must have the same length as the slice it is replacing.
(2)
- The optional argument *i* defaults to ``-1``, so that by default the last
- item is removed and returned.
+ The value *n* is an integer, or an object implementing
+ :meth:`~object.__index__`. Zero and negative values of *n* clear
+ the sequence. Items in the sequence are not copied; they are referenced
+ multiple times, as explained for ``s * n`` under :ref:`typesseq-common`.
-(3)
- :meth:`remove` raises :exc:`ValueError` when *x* is not found in *s*.
+.. rubric:: Mutable Sequence Methods
-(4)
- The :meth:`reverse` method modifies the sequence in place for economy of
- space when reversing a large sequence. To remind users that it operates by
- side effect, it does not return the reversed sequence.
+Mutable sequence types also support the following methods:
-(5)
- :meth:`clear` and :meth:`!copy` are included for consistency with the
- interfaces of mutable containers that don't support slicing operations
- (such as :class:`dict` and :class:`set`). :meth:`!copy` is not part of the
- :class:`collections.abc.MutableSequence` ABC, but most concrete
- mutable sequence classes provide it.
+.. method:: bytearray.append(value, /)
+ list.append(value, /)
+ :no-contents-entry:
+ :no-index-entry:
+ :no-typesetting:
+.. method:: sequence.append(value, /)
+
+ Append *value* to the end of the sequence.
+ This is equivalent to writing ``seq[len(seq):len(seq)] = [value]``.
+
+.. method:: bytearray.clear()
+ list.clear()
+ :no-contents-entry:
+ :no-index-entry:
+ :no-typesetting:
+.. method:: sequence.clear()
.. versionadded:: 3.3
- :meth:`clear` and :meth:`!copy` methods.
-(6)
- The value *n* is an integer, or an object implementing
- :meth:`~object.__index__`. Zero and negative values of *n* clear
- the sequence. Items in the sequence are not copied; they are referenced
- multiple times, as explained for ``s * n`` under :ref:`typesseq-common`.
+ Remove all items from *sequence*.
+ This is equivalent to writing ``del sequence[:]``.
+
+.. method:: bytearray.copy()
+ list.copy()
+ :no-contents-entry:
+ :no-index-entry:
+ :no-typesetting:
+.. method:: sequence.copy()
+
+ .. versionadded:: 3.3
+
+ Create a shallow copy of *sequence*.
+ This is equivalent to writing ``sequence[:]``.
+
+ .. hint:: The :meth:`!copy` method is not part of the
+ :class:`~collections.abc.MutableSequence` :class:`~abc.ABC`,
+ but most concrete mutable sequence types provide it.
+
+.. method:: bytearray.extend(iterable, /)
+ list.extend(iterable, /)
+ :no-contents-entry:
+ :no-index-entry:
+ :no-typesetting:
+.. method:: sequence.extend(iterable, /)
+
+ Extend *sequence* with the contents of *iterable*.
+ For the most part, this is the same as writing
+ ``seq[len(seq):len(seq)] = iterable``.
+
+.. method:: bytearray.insert(index, value, /)
+ list.insert(index, value, /)
+ :no-contents-entry:
+ :no-index-entry:
+ :no-typesetting:
+.. method:: sequence.insert(index, value, /)
+
+ Insert *value* into *sequence* at the given *index*.
+ This is equivalent to writing ``sequence[index:index] = [value]``.
+
+.. method:: bytearray.pop(index=-1, /)
+ list.pop(index=-1, /)
+ :no-contents-entry:
+ :no-index-entry:
+ :no-typesetting:
+.. method:: sequence.pop(index=-1, /)
+
+ Retrieve the item at *index* and also remove it from *sequence*.
+ By default, the last item in *sequence* is removed and returned.
+
+.. method:: bytearray.remove(value, /)
+ list.remove(value, /)
+ :no-contents-entry:
+ :no-index-entry:
+ :no-typesetting:
+.. method:: sequence.remove(value, /)
+
+ Remove the first item from *sequence* where ``sequence[i] == value``.
+
+ Raises :exc:`ValueError` if *value* is not found in *sequence*.
+
+.. method:: bytearray.reverse()
+ list.reverse()
+ :no-contents-entry:
+ :no-index-entry:
+ :no-typesetting:
+.. method:: sequence.reverse()
+
+ Reverse the items of *sequence* in place.
+ This method maintains economy of space when reversing a large sequence.
+ To remind users that it operates by side-effect, it returns ``None``.
.. _typesseq-list:
@@ -1262,7 +1330,7 @@ Lists are mutable sequences, typically used to store collections of
homogeneous items (where the precise degree of similarity will vary by
application).
-.. class:: list([iterable])
+.. class:: list(iterable=(), /)
Lists may be constructed in several ways:
@@ -1283,6 +1351,8 @@ application).
Many other operations also produce lists, including the :func:`sorted`
built-in.
+ Lists are :ref:`generic ` over the types of their items.
+
Lists implement all of the :ref:`common ` and
:ref:`mutable ` sequence operations. Lists also provide the
following additional method:
@@ -1343,7 +1413,7 @@ built-in). Tuples are also used for cases where an immutable sequence of
homogeneous data is needed (such as allowing storage in a :class:`set` or
:class:`dict` instance).
-.. class:: tuple([iterable])
+.. class:: tuple(iterable=(), /)
Tuples may be constructed in a number of ways:
@@ -1369,6 +1439,10 @@ homogeneous data is needed (such as allowing storage in a :class:`set` or
Tuples implement all of the :ref:`common ` sequence
operations.
+ Tuples are :ref:`generic ` over the types of their contents.
+ For more information, refer to
+ :ref:`the typing documentation on annotating tuples `.
+
For heterogeneous collections of data where access by name is clearer than
access by index, :func:`collections.namedtuple` may be a more appropriate
choice than a simple tuple object.
@@ -1385,8 +1459,8 @@ The :class:`range` type represents an immutable sequence of numbers and is
commonly used for looping a specific number of times in :keyword:`for`
loops.
-.. class:: range(stop)
- range(start, stop[, step])
+.. class:: range(stop, /)
+ range(start, stop, step=1, /)
The arguments to the range constructor must be integers (either built-in
:class:`int` or any object that implements the :meth:`~object.__index__` special
@@ -1497,8 +1571,8 @@ objects that compare equal might have different :attr:`~range.start`,
.. seealso::
* The `linspace recipe `_
- shows how to implement a lazy version of range suitable for floating
- point applications.
+ shows how to implement a lazy version of range suitable for floating-point
+ applications.
.. index::
single: string; text sequence type
@@ -1552,8 +1626,10 @@ multiple fragments.
.. index::
single: string; str (built-in class)
-.. class:: str(object='')
- str(object=b'', encoding='utf-8', errors='strict')
+.. class:: str(*, encoding='utf-8', errors='strict')
+ str(object)
+ str(object, encoding, errors='strict')
+ str(object, *, errors)
Return a :ref:`string ` version of *object*. If *object* is not
provided, returns the empty string. Otherwise, the behavior of ``str()``
@@ -1639,6 +1715,14 @@ expression support in the :mod:`re` module).
lowercase letter ``'ß'`` is equivalent to ``"ss"``. Since it is already
lowercase, :meth:`lower` would do nothing to ``'ß'``; :meth:`casefold`
converts it to ``"ss"``.
+ For example:
+
+ .. doctest::
+
+ >>> 'straße'.lower()
+ 'straße'
+ >>> 'straße'.casefold()
+ 'strasse'
The casefolding algorithm is
`described in section 3.13 'Default Case Folding' of the Unicode Standard
@@ -1647,12 +1731,18 @@ expression support in the :mod:`re` module).
.. versionadded:: 3.3
-.. method:: str.center(width[, fillchar])
+.. method:: str.center(width, fillchar=' ', /)
Return centered in a string of length *width*. Padding is done using the
specified *fillchar* (default is an ASCII space). The original string is
- returned if *width* is less than or equal to ``len(s)``.
+ returned if *width* is less than or equal to ``len(s)``. For example::
+ >>> 'Python'.center(10)
+ ' Python '
+ >>> 'Python'.center(10, '-')
+ '--Python--'
+ >>> 'Python'.center(4)
+ 'Python'
.. method:: str.count(sub[, start[, end]])
@@ -1662,8 +1752,18 @@ expression support in the :mod:`re` module).
interpreted as in slice notation.
If *sub* is empty, returns the number of empty strings between characters
- which is the length of the string plus one.
-
+ which is the length of the string plus one. For example::
+
+ >>> 'spam, spam, spam'.count('spam')
+ 3
+ >>> 'spam, spam, spam'.count('spam', 5)
+ 2
+ >>> 'spam, spam, spam'.count('spam', 5, 10)
+ 1
+ >>> 'spam, spam, spam'.count('eggs')
+ 0
+ >>> 'spam, spam, spam'.count('')
+ 17
.. method:: str.encode(encoding="utf-8", errors="strict")
@@ -1683,6 +1783,14 @@ expression support in the :mod:`re` module).
unless an encoding error actually occurs,
:ref:`devmode` is enabled
or a :ref:`debug build ` is used.
+ For example::
+
+ >>> encoded_str_to_bytes = 'Python'.encode()
+ >>> type(encoded_str_to_bytes)
+
+ >>> encoded_str_to_bytes
+ b'Python'
+
.. versionchanged:: 3.1
Added support for keyword arguments.
@@ -1697,7 +1805,19 @@ expression support in the :mod:`re` module).
Return ``True`` if the string ends with the specified *suffix*, otherwise return
``False``. *suffix* can also be a tuple of suffixes to look for. With optional
*start*, test beginning at that position. With optional *end*, stop comparing
- at that position.
+ at that position. Using *start* and *end* is equivalent to
+ ``str[start:end].endswith(suffix)``. For example::
+
+ >>> 'Python'.endswith('on')
+ True
+ >>> 'a tuple of suffixes'.endswith(('at', 'in'))
+ False
+ >>> 'a tuple of suffixes'.endswith(('at', 'es'))
+ True
+ >>> 'Python is amazing'.endswith('is', 0, 9)
+ True
+
+ See also :meth:`startswith` and :meth:`removesuffix`.
.. method:: str.expandtabs(tabsize=8)
@@ -1713,12 +1833,15 @@ expression support in the :mod:`re` module).
(``\n``) or return (``\r``), it is copied and the current column is reset to
zero. Any other character is copied unchanged and the current column is
incremented by one regardless of how the character is represented when
- printed.
+ printed. For example::
>>> '01\t012\t0123\t01234'.expandtabs()
'01 012 0123 01234'
>>> '01\t012\t0123\t01234'.expandtabs(4)
'01 012 0123 01234'
+ >>> print('01\t012\n0123\t01234'.expandtabs(4))
+ 01 012
+ 0123 01234
.. method:: str.find(sub[, start[, end]])
@@ -1726,6 +1849,14 @@ expression support in the :mod:`re` module).
Return the lowest index in the string where substring *sub* is found within
the slice ``s[start:end]``. Optional arguments *start* and *end* are
interpreted as in slice notation. Return ``-1`` if *sub* is not found.
+ For example::
+
+ >>> 'spam, spam, spam'.find('sp')
+ 0
+ >>> 'spam, spam, spam'.find('sp', 5)
+ 6
+
+ See also :meth:`rfind` and :meth:`index`.
.. note::
@@ -1744,10 +1875,16 @@ expression support in the :mod:`re` module).
``{}``. Each replacement field contains either the numeric index of a
positional argument, or the name of a keyword argument. Returns a copy of
the string where each replacement field is replaced with the string value of
- the corresponding argument.
+ the corresponding argument. For example:
+
+ .. doctest::
>>> "The sum of 1 + 2 is {0}".format(1+2)
'The sum of 1 + 2 is 3'
+ >>> "The sum of {a} + {b} is {answer}".format(answer=1+2, a=1, b=2)
+ 'The sum of 1 + 2 is 3'
+ >>> "{1} expects the {0} Inquisition!".format("Spanish", "Nobody")
+ 'Nobody expects the Spanish Inquisition!'
See :ref:`formatstrings` for a description of the various formatting options
that can be specified in format strings.
@@ -1768,7 +1905,7 @@ expression support in the :mod:`re` module).
cases.
-.. method:: str.format_map(mapping)
+.. method:: str.format_map(mapping, /)
Similar to ``str.format(**mapping)``, except that ``mapping`` is
used directly and not copied to a :class:`dict`. This is useful
@@ -1787,7 +1924,20 @@ expression support in the :mod:`re` module).
.. method:: str.index(sub[, start[, end]])
Like :meth:`~str.find`, but raise :exc:`ValueError` when the substring is
- not found.
+ not found. For example:
+
+ .. doctest::
+
+ >>> 'spam, spam, spam'.index('spam')
+ 0
+ >>> 'spam, spam, spam'.index('eggs')
+ Traceback (most recent call last):
+ File "", line 1, in
+ 'spam, spam, spam'.index('eggs')
+ ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
+ ValueError: substring not found
+
+ See also :meth:`rindex`.
.. method:: str.isalnum()
@@ -1795,7 +1945,18 @@ expression support in the :mod:`re` module).
Return ``True`` if all characters in the string are alphanumeric and there is at
least one character, ``False`` otherwise. A character ``c`` is alphanumeric if one
of the following returns ``True``: ``c.isalpha()``, ``c.isdecimal()``,
- ``c.isdigit()``, or ``c.isnumeric()``.
+ ``c.isdigit()``, or ``c.isnumeric()``. For example:
+
+ .. doctest::
+
+ >>> 'abc123'.isalnum()
+ True
+ >>> 'abc123!@#'.isalnum()
+ False
+ >>> ''.isalnum()
+ False
+ >>> ' '.isalnum()
+ False
.. method:: str.isalpha()
@@ -1804,16 +1965,35 @@ expression support in the :mod:`re` module).
one character, ``False`` otherwise. Alphabetic characters are those characters defined
in the Unicode character database as "Letter", i.e., those with general category
property being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is different
- from the `Alphabetic property defined in the section 4.10 'Letters, Alphabetic, and
+ from the `Alphabetic property defined in section 4.10 'Letters, Alphabetic, and
Ideographic' of the Unicode Standard
`_.
+ For example:
+
+ .. doctest::
+
+ >>> 'Letters and spaces'.isalpha()
+ False
+ >>> 'LettersOnly'.isalpha()
+ True
+ >>> 'µ'.isalpha() # non-ASCII characters can be considered alphabetical too
+ True
+
+ See :ref:`unicode-properties`.
.. method:: str.isascii()
Return ``True`` if the string is empty or all characters in the string are ASCII,
``False`` otherwise.
- ASCII characters have code points in the range U+0000-U+007F.
+ ASCII characters have code points in the range U+0000-U+007F. For example:
+
+ .. doctest::
+
+ >>> 'ASCII characters'.isascii()
+ True
+ >>> 'µ'.isascii()
+ False
.. versionadded:: 3.7
@@ -1823,9 +2003,18 @@ expression support in the :mod:`re` module).
Return ``True`` if all characters in the string are decimal
characters and there is at least one character, ``False``
otherwise. Decimal characters are those that can be used to form
- numbers in base 10, e.g. U+0660, ARABIC-INDIC DIGIT
+ numbers in base 10, such as U+0660, ARABIC-INDIC DIGIT
ZERO. Formally a decimal character is a character in the Unicode
- General Category "Nd".
+ General Category "Nd". For example:
+
+ .. doctest::
+
+ >>> '0123456789'.isdecimal()
+ True
+ >>> '٠١٢٣٤٥٦٧٨٩'.isdecimal() # Arabic-Indic digits zero to nine
+ True
+ >>> 'alphabetic'.isdecimal()
+ False
.. method:: str.isdigit()
@@ -1834,9 +2023,25 @@ expression support in the :mod:`re` module).
character, ``False`` otherwise. Digits include decimal characters and digits that need
special handling, such as the compatibility superscript digits.
This covers digits which cannot be used to form numbers in base 10,
- like the Kharosthi numbers. Formally, a digit is a character that has the
+ like the `Kharosthi numbers `__.
+ Formally, a digit is a character that has the
property value Numeric_Type=Digit or Numeric_Type=Decimal.
+ For example:
+
+ .. doctest::
+
+ >>> '0123456789'.isdigit()
+ True
+ >>> '٠١٢٣٤٥٦٧٨٩'.isdigit() # Arabic-Indic digits zero to nine
+ True
+ >>> '⅕'.isdigit() # Vulgar fraction one fifth
+ False
+ >>> '²'.isdecimal(), '²'.isdigit(), '²'.isnumeric()
+ (False, True, True)
+
+ See also :meth:`isdecimal` and :meth:`isnumeric`.
+
.. method:: str.isidentifier()
@@ -1871,17 +2076,48 @@ expression support in the :mod:`re` module).
that have the Unicode numeric value property, e.g. U+2155,
VULGAR FRACTION ONE FIFTH. Formally, numeric characters are those with the property
value Numeric_Type=Digit, Numeric_Type=Decimal or Numeric_Type=Numeric.
+ For example:
+
+ .. doctest::
+
+ >>> '0123456789'.isnumeric()
+ True
+ >>> '٠١٢٣٤٥٦٧٨٩'.isnumeric() # Arabic-Indic digits zero to nine
+ True
+ >>> '⅕'.isnumeric() # Vulgar fraction one fifth
+ True
+ >>> '²'.isdecimal(), '²'.isdigit(), '²'.isnumeric()
+ (False, True, True)
+
+ See also :meth:`isdecimal` and :meth:`isdigit`.
.. method:: str.isprintable()
- Return ``True`` if all characters in the string are printable or the string is
- empty, ``False`` otherwise. Nonprintable characters are those characters defined
- in the Unicode character database as "Other" or "Separator", excepting the
- ASCII space (0x20) which is considered printable. (Note that printable
- characters in this context are those which should not be escaped when
- :func:`repr` is invoked on a string. It has no bearing on the handling of
- strings written to :data:`sys.stdout` or :data:`sys.stderr`.)
+ Return ``True`` if all characters in the string are printable, ``False`` if it
+ contains at least one non-printable character.
+
+ Here "printable" means the character is suitable for :func:`repr` to use in
+ its output; "non-printable" means that :func:`repr` on built-in types will
+ hex-escape the character. It has no bearing on the handling of strings
+ written to :data:`sys.stdout` or :data:`sys.stderr`.
+
+ The printable characters are those which in the Unicode character database
+ (see :mod:`unicodedata`) have a general category in group Letter, Mark,
+ Number, Punctuation, or Symbol (L, M, N, P, or S); plus the ASCII space 0x20.
+ Nonprintable characters are those in group Separator or Other (Z or C),
+ except the ASCII space.
+
+ For example:
+
+ .. doctest::
+
+ >>> ''.isprintable(), ' '.isprintable()
+ (True, True)
+ >>> '\t'.isprintable(), '\n'.isprintable()
+ (False, False)
+
+ See also :meth:`isspace`.
.. method:: str.isspace()
@@ -1889,11 +2125,26 @@ expression support in the :mod:`re` module).
Return ``True`` if there are only whitespace characters in the string and there is
at least one character, ``False`` otherwise.
+ For example:
+
+ .. doctest::
+
+ >>> ''.isspace()
+ False
+ >>> ' '.isspace()
+ True
+ >>> '\t\n'.isspace() # TAB and BREAK LINE
+ True
+ >>> '\u3000'.isspace() # IDEOGRAPHIC SPACE
+ True
+
A character is *whitespace* if in the Unicode character database
(see :mod:`unicodedata`), either its general category is ``Zs``
("Separator, space"), or its bidirectional class is one of ``WS``,
``B``, or ``S``.
+ See also :meth:`isprintable`.
+
.. method:: str.istitle()
@@ -1901,6 +2152,19 @@ expression support in the :mod:`re` module).
character, for example uppercase characters may only follow uncased characters
and lowercase characters only cased ones. Return ``False`` otherwise.
+ For example:
+
+ .. doctest::
+
+ >>> 'Spam, Spam, Spam'.istitle()
+ True
+ >>> 'spam, spam, spam'.istitle()
+ False
+ >>> 'SPAM, SPAM, SPAM'.istitle()
+ False
+
+ See also :meth:`title`.
+
.. method:: str.isupper()
@@ -1920,32 +2184,59 @@ expression support in the :mod:`re` module).
.. _meth-str-join:
-.. method:: str.join(iterable)
+.. method:: str.join(iterable, /)
Return a string which is the concatenation of the strings in *iterable*.
A :exc:`TypeError` will be raised if there are any non-string values in
*iterable*, including :class:`bytes` objects. The separator between
- elements is the string providing this method.
+ elements is the string providing this method. For example:
+
+ .. doctest::
+ >>> ', '.join(['spam', 'spam', 'spam'])
+ 'spam, spam, spam'
+ >>> '-'.join('Python')
+ 'P-y-t-h-o-n'
-.. method:: str.ljust(width[, fillchar])
+ See also :meth:`split`.
+
+
+.. method:: str.ljust(width, fillchar=' ', /)
Return the string left justified in a string of length *width*. Padding is
done using the specified *fillchar* (default is an ASCII space). The
original string is returned if *width* is less than or equal to ``len(s)``.
+ For example:
+
+ .. doctest::
+
+ >>> 'Python'.ljust(10)
+ 'Python '
+ >>> 'Python'.ljust(10, '.')
+ 'Python....'
+ >>> 'Monty Python'.ljust(10, '.')
+ 'Monty Python'
+
+ See also :meth:`rjust`.
+
.. method:: str.lower()
Return a copy of the string with all the cased characters [4]_ converted to
- lowercase.
+ lowercase. For example:
+
+ .. doctest::
+
+ >>> 'Lower Method Example'.lower()
+ 'lower method example'
The lowercasing algorithm used is
`described in section 3.13 'Default Case Folding' of the Unicode Standard
`__.
-.. method:: str.lstrip([chars])
+.. method:: str.lstrip(chars=None, /)
Return a copy of the string with leading characters removed. The *chars*
argument is a string specifying the set of characters to be removed. If omitted
@@ -1966,7 +2257,8 @@ expression support in the :mod:`re` module).
'three!'
-.. staticmethod:: str.maketrans(x[, y[, z]])
+.. staticmethod:: str.maketrans(dict, /)
+ str.maketrans(from, to, remove='', /)
This static method returns a translation table usable for :meth:`str.translate`.
@@ -1976,24 +2268,39 @@ expression support in the :mod:`re` module).
converted to ordinals.
If there are two arguments, they must be strings of equal length, and in the
- resulting dictionary, each character in x will be mapped to the character at
- the same position in y. If there is a third argument, it must be a string,
+ resulting dictionary, each character in *from* will be mapped to the character at
+ the same position in *to*. If there is a third argument, it must be a string,
whose characters will be mapped to ``None`` in the result.
-.. method:: str.partition(sep)
+.. method:: str.partition(sep, /)
Split the string at the first occurrence of *sep*, and return a 3-tuple
containing the part before the separator, the separator itself, and the part
after the separator. If the separator is not found, return a 3-tuple containing
the string itself, followed by two empty strings.
+ For example:
+
+ .. doctest::
+
+ >>> 'Monty Python'.partition(' ')
+ ('Monty', ' ', 'Python')
+ >>> "Monty Python's Flying Circus".partition(' ')
+ ('Monty', ' ', "Python's Flying Circus")
+ >>> 'Monty Python'.partition('-')
+ ('Monty Python', '', '')
+
+ See also :meth:`rpartition`.
+
.. method:: str.removeprefix(prefix, /)
If the string starts with the *prefix* string, return
``string[len(prefix):]``. Otherwise, return a copy of the original
- string::
+ string:
+
+ .. doctest::
>>> 'TestHook'.removeprefix('Test')
'Hook'
@@ -2002,12 +2309,16 @@ expression support in the :mod:`re` module).
.. versionadded:: 3.9
+ See also :meth:`removesuffix` and :meth:`startswith`.
+
.. method:: str.removesuffix(suffix, /)
If the string ends with the *suffix* string and that *suffix* is not empty,
return ``string[:-len(suffix)]``. Otherwise, return a copy of the
- original string::
+ original string:
+
+ .. doctest::
>>> 'MiscTests'.removesuffix('Tests')
'Misc'
@@ -2016,12 +2327,22 @@ expression support in the :mod:`re` module).
.. versionadded:: 3.9
+ See also :meth:`removeprefix` and :meth:`endswith`.
-.. method:: str.replace(old, new, count=-1)
+
+.. method:: str.replace(old, new, /, count=-1)
Return a copy of the string with all occurrences of substring *old* replaced by
*new*. If *count* is given, only the first *count* occurrences are replaced.
If *count* is not specified or ``-1``, then all occurrences are replaced.
+ For example:
+
+ .. doctest::
+
+ >>> 'spam, spam, spam'.replace('spam', 'eggs')
+ 'eggs, eggs, eggs'
+ >>> 'spam, spam, spam'.replace('spam', 'eggs', 1)
+ 'eggs, spam, spam'
.. versionchanged:: 3.13
*count* is now supported as a keyword argument.
@@ -2032,51 +2353,105 @@ expression support in the :mod:`re` module).
Return the highest index in the string where substring *sub* is found, such
that *sub* is contained within ``s[start:end]``. Optional arguments *start*
and *end* are interpreted as in slice notation. Return ``-1`` on failure.
+ For example:
+
+ .. doctest::
+
+ >>> 'spam, spam, spam'.rfind('sp')
+ 12
+ >>> 'spam, spam, spam'.rfind('sp', 0, 10)
+ 6
+
+ See also :meth:`find` and :meth:`rindex`.
.. method:: str.rindex(sub[, start[, end]])
Like :meth:`rfind` but raises :exc:`ValueError` when the substring *sub* is not
found.
+ For example:
+ .. doctest::
+
+ >>> 'spam, spam, spam'.rindex('spam')
+ 12
+ >>> 'spam, spam, spam'.rindex('eggs')
+ Traceback (most recent call last):
+ File "", line 1, in
+ 'spam, spam, spam'.rindex('eggs')
+ ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
+ ValueError: substring not found
-.. method:: str.rjust(width[, fillchar])
+ See also :meth:`index` and :meth:`find`.
+
+
+.. method:: str.rjust(width, fillchar=' ', /)
Return the string right justified in a string of length *width*. Padding is
done using the specified *fillchar* (default is an ASCII space). The
original string is returned if *width* is less than or equal to ``len(s)``.
+ For example:
-.. method:: str.rpartition(sep)
+ .. doctest::
+
+ >>> 'Python'.rjust(10)
+ ' Python'
+ >>> 'Python'.rjust(10, '.')
+ '....Python'
+ >>> 'Monty Python'.rjust(10, '.')
+ 'Monty Python'
+
+ See also :meth:`ljust` and :meth:`zfill`.
+
+
+.. method:: str.rpartition(sep, /)
Split the string at the last occurrence of *sep*, and return a 3-tuple
containing the part before the separator, the separator itself, and the part
after the separator. If the separator is not found, return a 3-tuple containing
two empty strings, followed by the string itself.
+ For example:
+
+ .. doctest::
+
+ >>> 'Monty Python'.rpartition(' ')
+ ('Monty', ' ', 'Python')
+ >>> "Monty Python's Flying Circus".rpartition(' ')
+ ("Monty Python's Flying", ' ', 'Circus')
+ >>> 'Monty Python'.rpartition('-')
+ ('', '', 'Monty Python')
+
+ See also :meth:`partition`.
+
.. method:: str.rsplit(sep=None, maxsplit=-1)
Return a list of the words in the string, using *sep* as the delimiter string.
If *maxsplit* is given, at most *maxsplit* splits are done, the *rightmost*
- ones. If *sep* is not specified or ``None``, any whitespace string is a
+ ones. If *sep* is not specified or ``None``, any
+ :meth:`whitespace ` string is a
separator. Except for splitting from the right, :meth:`rsplit` behaves like
:meth:`split` which is described in detail below.
-.. method:: str.rstrip([chars])
+.. method:: str.rstrip(chars=None, /)
Return a copy of the string with trailing characters removed. The *chars*
argument is a string specifying the set of characters to be removed. If omitted
or ``None``, the *chars* argument defaults to removing whitespace. The *chars*
- argument is not a suffix; rather, all combinations of its values are stripped::
+ argument is not a suffix; rather, all combinations of its values are stripped.
+ For example:
+
+ .. doctest::
>>> ' spacious '.rstrip()
' spacious'
>>> 'mississippi'.rstrip('ipz')
'mississ'
- See :meth:`str.removesuffix` for a method that will remove a single suffix
+ See :meth:`removesuffix` for a method that will remove a single suffix
string rather than all of a set of characters. For example::
>>> 'Monty Python'.rstrip(' Python')
@@ -2084,6 +2459,9 @@ expression support in the :mod:`re` module).
>>> 'Monty Python'.removesuffix(' Python')
'Monty'
+ See also :meth:`strip`.
+
+
.. method:: str.split(sep=None, maxsplit=-1)
Return a list of the words in the string, using *sep* as the delimiter
@@ -2095,10 +2473,13 @@ expression support in the :mod:`re` module).
If *sep* is given, consecutive delimiters are not grouped together and are
deemed to delimit empty strings (for example, ``'1,,2'.split(',')`` returns
``['1', '', '2']``). The *sep* argument may consist of multiple characters
- (for example, ``'1<>2<>3'.split('<>')`` returns ``['1', '2', '3']``).
- Splitting an empty string with a specified separator returns ``['']``.
+ as a single delimiter (to split with multiple delimiters, use
+ :func:`re.split`). Splitting an empty string with a specified separator
+ returns ``['']``.
- For example::
+ For example:
+
+ .. doctest::
>>> '1,2,3'.split(',')
['1', '2', '3']
@@ -2106,15 +2487,20 @@ expression support in the :mod:`re` module).
['1', '2,3']
>>> '1,2,,3,'.split(',')
['1', '2', '', '3', '']
+ >>> '1<>2<>3<4'.split('<>')
+ ['1', '2', '3<4']
If *sep* is not specified or is ``None``, a different splitting algorithm is
- applied: runs of consecutive whitespace are regarded as a single separator,
+ applied: runs of consecutive :meth:`whitespace ` are regarded
+ as a single separator,
and the result will contain no empty strings at the start or end if the
string has leading or trailing whitespace. Consequently, splitting an empty
string or a string consisting of just whitespace with a ``None`` separator
returns ``[]``.
- For example::
+ For example:
+
+ .. doctest::
>>> '1 2 3'.split()
['1', '2', '3']
@@ -2123,6 +2509,22 @@ expression support in the :mod:`re` module).
>>> ' 1 2 3 '.split()
['1', '2', '3']
+ If *sep* is not specified or is ``None`` and *maxsplit* is ``0``, only
+ leading runs of consecutive whitespace are considered.
+
+ For example:
+
+ .. doctest::
+
+ >>> "".split(None, 0)
+ []
+ >>> " ".split(None, 0)
+ []
+ >>> " foo ".split(maxsplit=0)
+ ['foo ']
+
+ See also :meth:`join` and :meth:`rsplit`.
+
.. index::
single: universal newlines; str.splitlines method
@@ -2197,14 +2599,33 @@ expression support in the :mod:`re` module).
test string beginning at that position. With optional *end*, stop comparing
string at that position.
+ For example:
+
+ .. doctest::
+
+ >>> 'Python'.startswith('Py')
+ True
+ >>> 'a tuple of prefixes'.startswith(('at', 'a'))
+ True
+ >>> 'Python is amazing'.startswith('is', 7)
+ True
+
+ See also :meth:`endswith` and :meth:`removeprefix`.
-.. method:: str.strip([chars])
+
+.. method:: str.strip(chars=None, /)
Return a copy of the string with the leading and trailing characters removed.
The *chars* argument is a string specifying the set of characters to be removed.
If omitted or ``None``, the *chars* argument defaults to removing whitespace.
The *chars* argument is not a prefix or suffix; rather, all combinations of its
- values are stripped::
+ values are stripped.
+
+ Whitespace characters are defined by :meth:`str.isspace`.
+
+ For example:
+
+ .. doctest::
>>> ' spacious '.strip()
'spacious'
@@ -2215,18 +2636,37 @@ expression support in the :mod:`re` module).
from the string. Characters are removed from the leading end until
reaching a string character that is not contained in the set of
characters in *chars*. A similar action takes place on the trailing end.
- For example::
+
+ For example:
+
+ .. doctest::
>>> comment_string = '#....... Section 3.2.1 Issue #32 .......'
>>> comment_string.strip('.#! ')
'Section 3.2.1 Issue #32'
+ See also :meth:`rstrip`.
+
.. method:: str.swapcase()
Return a copy of the string with uppercase characters converted to lowercase and
- vice versa. Note that it is not necessarily true that
- ``s.swapcase().swapcase() == s``.
+ vice versa. For example:
+
+ .. doctest::
+
+ >>> 'Hello World'.swapcase()
+ 'hELLO wORLD'
+
+ Note that it is not necessarily true that ``s.swapcase().swapcase() == s``.
+ For example:
+
+ .. doctest::
+
+ >>> 'straße'.swapcase().swapcase()
+ 'strasse'
+
+ See also :meth:`str.lower` and :meth:`str.upper`.
.. method:: str.title()
@@ -2262,8 +2702,10 @@ expression support in the :mod:`re` module).
>>> titlecase("they're bill's friends.")
"They're Bill's Friends."
+ See also :meth:`istitle`.
+
-.. method:: str.translate(table)
+.. method:: str.translate(table, /)
Return a copy of the string in which each character has been mapped through
the given translation table. The table must be an object that implements
@@ -2294,7 +2736,7 @@ expression support in the :mod:`re` module).
`__.
-.. method:: str.zfill(width)
+.. method:: str.zfill(width, /)
Return a copy of the string left filled with ASCII ``'0'`` digits to
make a string of length *width*. A leading sign prefix (``'+'``/``'-'``)
@@ -2302,13 +2744,157 @@ expression support in the :mod:`re` module).
than before. The original string is returned if *width* is less than
or equal to ``len(s)``.
- For example::
+ For example:
+
+ .. doctest::
>>> "42".zfill(5)
'00042'
>>> "-42".zfill(5)
'-0042'
+ See also :meth:`rjust`.
+
+
+.. index::
+ single: ! formatted string literal
+ single: formatted string literals
+ single: ! f-string
+ single: f-strings
+ single: fstring
+ single: interpolated string literal
+ single: string; formatted literal
+ single: string; interpolated literal
+ single: {} (curly brackets); in formatted string literal
+ single: ! (exclamation mark); in formatted string literal
+ single: : (colon); in formatted string literal
+ single: = (equals); for help in debugging using string literals
+
+Formatted String Literals (f-strings)
+-------------------------------------
+
+.. versionadded:: 3.6
+.. versionchanged:: 3.7
+ The :keyword:`await` and :keyword:`async for` can be used in expressions
+ within f-strings.
+.. versionchanged:: 3.8
+ Added the debugging operator (``=``)
+.. versionchanged:: 3.12
+ Many restrictions on expressions within f-strings have been removed.
+ Notably, nested strings, comments, and backslashes are now permitted.
+
+An :dfn:`f-string` (formally a :dfn:`formatted string literal`) is
+a string literal that is prefixed with ``f`` or ``F``.
+This type of string literal allows embedding arbitrary Python expressions
+within *replacement fields*, which are delimited by curly brackets (``{}``).
+These expressions are evaluated at runtime, similarly to :meth:`str.format`,
+and are converted into regular :class:`str` objects.
+For example:
+
+.. doctest::
+
+ >>> who = 'nobody'
+ >>> nationality = 'Spanish'
+ >>> f'{who.title()} expects the {nationality} Inquisition!'
+ 'Nobody expects the Spanish Inquisition!'
+
+It is also possible to use a multi line f-string:
+
+.. doctest::
+
+ >>> f'''This is a string
+ ... on two lines'''
+ 'This is a string\non two lines'
+
+A single opening curly bracket, ``'{'``, marks a *replacement field* that
+can contain any Python expression:
+
+.. doctest::
+
+ >>> nationality = 'Spanish'
+ >>> f'The {nationality} Inquisition!'
+ 'The Spanish Inquisition!'
+
+To include a literal ``{`` or ``}``, use a double bracket:
+
+.. doctest::
+
+ >>> x = 42
+ >>> f'{{x}} is {x}'
+ '{x} is 42'
+
+Functions can also be used, and :ref:`format specifiers `:
+
+.. doctest::
+
+ >>> from math import sqrt
+ >>> f'√2 \N{ALMOST EQUAL TO} {sqrt(2):.5f}'
+ '√2 ≈ 1.41421'
+
+Any non-string expression is converted using :func:`str`, by default:
+
+.. doctest::
+
+ >>> from fractions import Fraction
+ >>> f'{Fraction(1, 3)}'
+ '1/3'
+
+To use an explicit conversion, use the ``!`` (exclamation mark) operator,
+followed by any of the valid formats, which are:
+
+========== ==============
+Conversion Meaning
+========== ==============
+``!a`` :func:`ascii`
+``!r`` :func:`repr`
+``!s`` :func:`str`
+========== ==============
+
+For example:
+
+.. doctest::
+
+ >>> from fractions import Fraction
+ >>> f'{Fraction(1, 3)!s}'
+ '1/3'
+ >>> f'{Fraction(1, 3)!r}'
+ 'Fraction(1, 3)'
+ >>> question = '¿Dónde está el Presidente?'
+ >>> print(f'{question!a}')
+ '\xbfD\xf3nde est\xe1 el Presidente?'
+
+While debugging it may be helpful to see both the expression and its value,
+by using the equals sign (``=``) after the expression.
+This preserves spaces within the brackets, and can be used with a converter.
+By default, the debugging operator uses the :func:`repr` (``!r``) conversion.
+For example:
+
+.. doctest::
+
+ >>> from fractions import Fraction
+ >>> calculation = Fraction(1, 3)
+ >>> f'{calculation=}'
+ 'calculation=Fraction(1, 3)'
+ >>> f'{calculation = }'
+ 'calculation = Fraction(1, 3)'
+ >>> f'{calculation = !s}'
+ 'calculation = 1/3'
+
+Once the output has been evaluated, it can be formatted using a
+:ref:`format specifier ` following a colon (``':'``).
+After the expression has been evaluated, and possibly converted to a string,
+the :meth:`!__format__` method of the result is called with the format specifier,
+or the empty string if no format specifier is given.
+The formatted result is then used as the final value for the replacement field.
+For example:
+
+.. doctest::
+
+ >>> from fractions import Fraction
+ >>> f'{Fraction(1, 7):.6f}'
+ '0.142857'
+ >>> f'{Fraction(1, 7):_^+10}'
+ '___+1/7___'
.. _old-string-formatting:
@@ -2439,19 +3025,19 @@ The conversion types are:
+------------+-----------------------------------------------------+-------+
| ``'X'`` | Signed hexadecimal (uppercase). | \(2) |
+------------+-----------------------------------------------------+-------+
-| ``'e'`` | Floating point exponential format (lowercase). | \(3) |
+| ``'e'`` | Floating-point exponential format (lowercase). | \(3) |
+------------+-----------------------------------------------------+-------+
-| ``'E'`` | Floating point exponential format (uppercase). | \(3) |
+| ``'E'`` | Floating-point exponential format (uppercase). | \(3) |
+------------+-----------------------------------------------------+-------+
-| ``'f'`` | Floating point decimal format. | \(3) |
+| ``'f'`` | Floating-point decimal format. | \(3) |
+------------+-----------------------------------------------------+-------+
-| ``'F'`` | Floating point decimal format. | \(3) |
+| ``'F'`` | Floating-point decimal format. | \(3) |
+------------+-----------------------------------------------------+-------+
-| ``'g'`` | Floating point format. Uses lowercase exponential | \(4) |
+| ``'g'`` | Floating-point format. Uses lowercase exponential | \(4) |
| | format if exponent is less than -4 or not less than | |
| | precision, decimal format otherwise. | |
+------------+-----------------------------------------------------+-------+
-| ``'G'`` | Floating point format. Uses uppercase exponential | \(4) |
+| ``'G'`` | Floating-point format. Uses uppercase exponential | \(4) |
| | format if exponent is less than -4 or not less than | |
| | precision, decimal format otherwise. | |
+------------+-----------------------------------------------------+-------+
@@ -2471,6 +3057,10 @@ The conversion types are:
| | character in the result. | |
+------------+-----------------------------------------------------+-------+
+For floating-point formats, the result should be correctly rounded to a given
+precision ``p`` of digits after the decimal point. The rounding mode matches
+that of the :func:`round` builtin.
+
Notes:
(1)
@@ -2545,7 +3135,8 @@ binary protocols are based on the ASCII text encoding, bytes objects offer
several methods that are only valid when working with ASCII compatible
data and are closely related to string objects in a variety of other ways.
-.. class:: bytes([source[, encoding[, errors]]])
+.. class:: bytes(source=b'')
+ bytes(source, encoding, errors='strict')
Firstly, the syntax for bytes literals is largely the same as that for string
literals, except that a ``b`` prefix is added:
@@ -2585,7 +3176,7 @@ data and are closely related to string objects in a variety of other ways.
numbers are a commonly used format for describing binary data. Accordingly,
the bytes type has an additional class method to read data in that format:
- .. classmethod:: fromhex(string)
+ .. classmethod:: fromhex(string, /)
This :class:`bytes` class method returns a bytes object, decoding the
given string object. The string must contain two hexadecimal digits per
@@ -2601,7 +3192,8 @@ data and are closely related to string objects in a variety of other ways.
A reverse conversion function exists to transform a bytes object into its
hexadecimal representation.
- .. method:: hex([sep[, bytes_per_sep]])
+ .. method:: hex(*, bytes_per_sep=1)
+ hex(sep, bytes_per_sep=1)
Return a string object containing two hexadecimal digits for each
byte in the instance.
@@ -2650,7 +3242,8 @@ Bytearray Objects
:class:`bytearray` objects are a mutable counterpart to :class:`bytes`
objects.
-.. class:: bytearray([source[, encoding[, errors]]])
+.. class:: bytearray(source=b'')
+ bytearray(source, encoding, errors='strict')
There is no dedicated literal syntax for bytearray objects, instead
they are always created by calling the constructor:
@@ -2670,9 +3263,9 @@ objects.
numbers are a commonly used format for describing binary data. Accordingly,
the bytearray type has an additional class method to read data in that format:
- .. classmethod:: fromhex(string)
+ .. classmethod:: fromhex(string, /)
- This :class:`bytearray` class method returns bytearray object, decoding
+ This :class:`bytearray` class method returns a bytearray object, decoding
the given string object. The string must contain two hexadecimal digits
per byte, with ASCII whitespace being ignored.
@@ -2686,7 +3279,8 @@ objects.
A reverse conversion function exists to transform a bytearray object into its
hexadecimal representation.
- .. method:: hex([sep[, bytes_per_sep]])
+ .. method:: hex(*, bytes_per_sep=1)
+ hex(sep, bytes_per_sep=1)
Return a string object containing two hexadecimal digits for each
byte in the instance.
@@ -2892,8 +3486,8 @@ arbitrary binary data.
Also accept an integer in the range 0 to 255 as the subsequence.
-.. method:: bytes.join(iterable)
- bytearray.join(iterable)
+.. method:: bytes.join(iterable, /)
+ bytearray.join(iterable, /)
Return a bytes or bytearray object which is the concatenation of the
binary data sequences in *iterable*. A :exc:`TypeError` will be raised
@@ -2903,8 +3497,8 @@ arbitrary binary data.
bytearray object providing this method.
-.. staticmethod:: bytes.maketrans(from, to)
- bytearray.maketrans(from, to)
+.. staticmethod:: bytes.maketrans(from, to, /)
+ bytearray.maketrans(from, to, /)
This static method returns a translation table usable for
:meth:`bytes.translate` that will map each character in *from* into the
@@ -2914,8 +3508,8 @@ arbitrary binary data.
.. versionadded:: 3.1
-.. method:: bytes.partition(sep)
- bytearray.partition(sep)
+.. method:: bytes.partition(sep, /)
+ bytearray.partition(sep, /)
Split the sequence at the first occurrence of *sep*, and return a 3-tuple
containing the part before the separator, the separator itself or its
@@ -2927,8 +3521,8 @@ arbitrary binary data.
The separator to search for may be any :term:`bytes-like object`.
-.. method:: bytes.replace(old, new[, count])
- bytearray.replace(old, new[, count])
+.. method:: bytes.replace(old, new, count=-1, /)
+ bytearray.replace(old, new, count=-1, /)
Return a copy of the sequence with all occurrences of subsequence *old*
replaced by *new*. If the optional argument *count* is given, only the
@@ -2971,8 +3565,8 @@ arbitrary binary data.
Also accept an integer in the range 0 to 255 as the subsequence.
-.. method:: bytes.rpartition(sep)
- bytearray.rpartition(sep)
+.. method:: bytes.rpartition(sep, /)
+ bytearray.rpartition(sep, /)
Split the sequence at the last occurrence of *sep*, and return a 3-tuple
containing the part before the separator, the separator itself or its
@@ -3022,8 +3616,8 @@ with arbitrary binary data by passing appropriate arguments. Note that all of
the bytearray methods in this section do *not* operate in place, and instead
produce new objects.
-.. method:: bytes.center(width[, fillbyte])
- bytearray.center(width[, fillbyte])
+.. method:: bytes.center(width, fillbyte=b' ', /)
+ bytearray.center(width, fillbyte=b' ', /)
Return a copy of the object centered in a sequence of length *width*.
Padding is done using the specified *fillbyte* (default is an ASCII
@@ -3036,8 +3630,8 @@ produce new objects.
it always produces a new object, even if no changes were made.
-.. method:: bytes.ljust(width[, fillbyte])
- bytearray.ljust(width[, fillbyte])
+.. method:: bytes.ljust(width, fillbyte=b' ', /)
+ bytearray.ljust(width, fillbyte=b' ', /)
Return a copy of the object left justified in a sequence of length *width*.
Padding is done using the specified *fillbyte* (default is an ASCII
@@ -3050,14 +3644,14 @@ produce new objects.
it always produces a new object, even if no changes were made.
-.. method:: bytes.lstrip([chars])
- bytearray.lstrip([chars])
+.. method:: bytes.lstrip(bytes=None, /)
+ bytearray.lstrip(bytes=None, /)
Return a copy of the sequence with specified leading bytes removed. The
- *chars* argument is a binary sequence specifying the set of byte values to
- be removed - the name refers to the fact this method is usually used with
- ASCII characters. If omitted or ``None``, the *chars* argument defaults
- to removing ASCII whitespace. The *chars* argument is not a prefix;
+ *bytes* argument is a binary sequence specifying the set of byte values to
+ be removed. If omitted or ``None``, the *bytes* argument defaults
+ to removing :meth:`ASCII whitespace `.
+ The *bytes* argument is not a prefix;
rather, all combinations of its values are stripped::
>>> b' spacious '.lstrip()
@@ -3081,8 +3675,8 @@ produce new objects.
it always produces a new object, even if no changes were made.
-.. method:: bytes.rjust(width[, fillbyte])
- bytearray.rjust(width[, fillbyte])
+.. method:: bytes.rjust(width, fillbyte=b' ', /)
+ bytearray.rjust(width, fillbyte=b' ', /)
Return a copy of the object right justified in a sequence of length *width*.
Padding is done using the specified *fillbyte* (default is an ASCII
@@ -3101,19 +3695,20 @@ produce new objects.
Split the binary sequence into subsequences of the same type, using *sep*
as the delimiter string. If *maxsplit* is given, at most *maxsplit* splits
are done, the *rightmost* ones. If *sep* is not specified or ``None``,
- any subsequence consisting solely of ASCII whitespace is a separator.
+ any subsequence consisting solely of
+ :meth:`ASCII whitespace ` is a separator.
Except for splitting from the right, :meth:`rsplit` behaves like
:meth:`split` which is described in detail below.
-.. method:: bytes.rstrip([chars])
- bytearray.rstrip([chars])
+.. method:: bytes.rstrip(bytes=None, /)
+ bytearray.rstrip(bytes=None, /)
Return a copy of the sequence with specified trailing bytes removed. The
- *chars* argument is a binary sequence specifying the set of byte values to
- be removed - the name refers to the fact this method is usually used with
- ASCII characters. If omitted or ``None``, the *chars* argument defaults to
- removing ASCII whitespace. The *chars* argument is not a suffix; rather,
+ *bytes* argument is a binary sequence specifying the set of byte values to
+ be removed. If omitted or ``None``, the *bytes* argument defaults to
+ removing :meth:`ASCII whitespace `.
+ The *bytes* argument is not a suffix; rather,
all combinations of its values are stripped::
>>> b' spacious '.rstrip()
@@ -3149,10 +3744,9 @@ produce new objects.
If *sep* is given, consecutive delimiters are not grouped together and are
deemed to delimit empty subsequences (for example, ``b'1,,2'.split(b',')``
returns ``[b'1', b'', b'2']``). The *sep* argument may consist of a
- multibyte sequence (for example, ``b'1<>2<>3'.split(b'<>')`` returns
- ``[b'1', b'2', b'3']``). Splitting an empty sequence with a specified
- separator returns ``[b'']`` or ``[bytearray(b'')]`` depending on the type
- of object being split. The *sep* argument may be any
+ multibyte sequence as a single delimiter. Splitting an empty sequence with
+ a specified separator returns ``[b'']`` or ``[bytearray(b'')]`` depending
+ on the type of object being split. The *sep* argument may be any
:term:`bytes-like object`.
For example::
@@ -3163,9 +3757,12 @@ produce new objects.
[b'1', b'2,3']
>>> b'1,2,,3,'.split(b',')
[b'1', b'2', b'', b'3', b'']
+ >>> b'1<>2<>3<4'.split(b'<>')
+ [b'1', b'2', b'3<4']
If *sep* is not specified or is ``None``, a different splitting algorithm
- is applied: runs of consecutive ASCII whitespace are regarded as a single
+ is applied: runs of consecutive :meth:`ASCII whitespace `
+ are regarded as a single
separator, and the result will contain no empty strings at the start or
end if the sequence has leading or trailing whitespace. Consequently,
splitting an empty sequence or a sequence consisting solely of ASCII
@@ -3182,14 +3779,14 @@ produce new objects.
[b'1', b'2', b'3']
-.. method:: bytes.strip([chars])
- bytearray.strip([chars])
+.. method:: bytes.strip(bytes=None, /)
+ bytearray.strip(bytes=None, /)
Return a copy of the sequence with specified leading and trailing bytes
- removed. The *chars* argument is a binary sequence specifying the set of
- byte values to be removed - the name refers to the fact this method is
- usually used with ASCII characters. If omitted or ``None``, the *chars*
- argument defaults to removing ASCII whitespace. The *chars* argument is
+ removed. The *bytes* argument is a binary sequence specifying the set of
+ byte values to be removed. If omitted or ``None``, the *bytes*
+ argument defaults to removing :meth:`ASCII whitespace `.
+ The *bytes* argument is
not a prefix or suffix; rather, all combinations of its values are
stripped::
@@ -3436,7 +4033,7 @@ place, and instead produce new objects.
``b'abcdefghijklmnopqrstuvwxyz'``. Uppercase ASCII characters
are those byte values in the sequence ``b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'``.
- Unlike :func:`str.swapcase()`, it is always the case that
+ Unlike :func:`str.swapcase`, it is always the case that
``bin.swapcase().swapcase() == bin`` for the binary versions. Case
conversions are symmetrical in ASCII, even though that is not generally
true for arbitrary Unicode code points.
@@ -3511,8 +4108,8 @@ place, and instead produce new objects.
always produces a new object, even if no changes were made.
-.. method:: bytes.zfill(width)
- bytearray.zfill(width)
+.. method:: bytes.zfill(width, /)
+ bytearray.zfill(width, /)
Return a copy of the sequence left filled with ASCII ``b'0'`` digits to
make a sequence of length *width*. A leading sign prefix (``b'+'``/
@@ -3563,7 +4160,7 @@ the ``%`` operator (modulo).
This is also known as the bytes *formatting* or *interpolation* operator.
Given ``format % values`` (where *format* is a bytes object), ``%`` conversion
specifications in *format* are replaced with zero or more elements of *values*.
-The effect is similar to using the :c:func:`sprintf` in the C language.
+The effect is similar to using the :c:func:`sprintf` function in the C language.
If *format* requires a single argument, *values* may be a single non-tuple
object. [5]_ Otherwise, *values* must be a tuple with exactly the number of
@@ -3657,19 +4254,19 @@ The conversion types are:
+------------+-----------------------------------------------------+-------+
| ``'X'`` | Signed hexadecimal (uppercase). | \(2) |
+------------+-----------------------------------------------------+-------+
-| ``'e'`` | Floating point exponential format (lowercase). | \(3) |
+| ``'e'`` | Floating-point exponential format (lowercase). | \(3) |
+------------+-----------------------------------------------------+-------+
-| ``'E'`` | Floating point exponential format (uppercase). | \(3) |
+| ``'E'`` | Floating-point exponential format (uppercase). | \(3) |
+------------+-----------------------------------------------------+-------+
-| ``'f'`` | Floating point decimal format. | \(3) |
+| ``'f'`` | Floating-point decimal format. | \(3) |
+------------+-----------------------------------------------------+-------+
-| ``'F'`` | Floating point decimal format. | \(3) |
+| ``'F'`` | Floating-point decimal format. | \(3) |
+------------+-----------------------------------------------------+-------+
-| ``'g'`` | Floating point format. Uses lowercase exponential | \(4) |
+| ``'g'`` | Floating-point format. Uses lowercase exponential | \(4) |
| | format if exponent is less than -4 or not less than | |
| | precision, decimal format otherwise. | |
+------------+-----------------------------------------------------+-------+
-| ``'G'`` | Floating point format. Uses uppercase exponential | \(4) |
+| ``'G'`` | Floating-point format. Uses uppercase exponential | \(4) |
| | format if exponent is less than -4 or not less than | |
| | precision, decimal format otherwise. | |
+------------+-----------------------------------------------------+-------+
@@ -3761,7 +4358,7 @@ copying.
byte, but other types such as :class:`array.array` may have bigger elements.
``len(view)`` is equal to the length of :class:`~memoryview.tolist`, which
- is the nested list representation of the view. If ``view.ndim = 1``,
+ is the nested list representation of the view. If ``view.ndim == 1``,
this is equal to the number of elements in the view.
.. versionchanged:: 3.12
@@ -3846,7 +4443,7 @@ copying.
:class:`collections.abc.Sequence`
.. versionchanged:: 3.5
- memoryviews can now be indexed with tuple of integers.
+ memoryviews can now be indexed with a tuple of integers.
:class:`memoryview` has several methods:
@@ -3891,7 +4488,7 @@ copying.
>>> a == b
False
- Note that, as with floating point numbers, ``v is w`` does *not* imply
+ Note that, as with floating-point numbers, ``v is w`` does *not* imply
``v == w`` for memoryview objects.
.. versionchanged:: 3.3
@@ -3921,7 +4518,8 @@ copying.
in-memory Fortran order is preserved. For non-contiguous views, the
data is converted to C first. *order=None* is the same as *order='C'*.
- .. method:: hex([sep[, bytes_per_sep]])
+ .. method:: hex(*, bytes_per_sep=1)
+ hex(sep, bytes_per_sep=1)
Return a string object containing two hexadecimal digits for each
byte in the buffer. ::
@@ -3982,7 +4580,7 @@ copying.
dangling resources) as soon as possible.
After this method has been called, any further operation on the view
- raises a :class:`ValueError` (except :meth:`release()` itself which can
+ raises a :class:`ValueError` (except :meth:`release` itself which can
be called multiple times)::
>>> m = memoryview(b'abc')
@@ -4006,7 +4604,8 @@ copying.
.. versionadded:: 3.2
- .. method:: cast(format[, shape])
+ .. method:: cast(format, /)
+ cast(format, shape, /)
Cast a memoryview to a new format or shape. *shape* defaults to
``[byte_length//new_itemsize]``, which means that the result view
@@ -4253,8 +4852,8 @@ of elements within braces, for example: ``{'jack', 'sjoerd'}``, in addition to t
The constructors for both classes work the same:
-.. class:: set([iterable])
- frozenset([iterable])
+.. class:: set(iterable=(), /)
+ frozenset(iterable=(), /)
Return a new set or frozenset object whose elements are taken from
*iterable*. The elements of a set must be :term:`hashable`. To
@@ -4262,165 +4861,174 @@ The constructors for both classes work the same:
objects. If *iterable* is not specified, a new empty set is
returned.
- Sets can be created by several means:
+Sets can be created by several means:
- * Use a comma-separated list of elements within braces: ``{'jack', 'sjoerd'}``
- * Use a set comprehension: ``{c for c in 'abracadabra' if c not in 'abc'}``
- * Use the type constructor: ``set()``, ``set('foobar')``, ``set(['a', 'b', 'foo'])``
+* Use a comma-separated list of elements within braces: ``{'jack', 'sjoerd'}``
+* Use a set comprehension: ``{c for c in 'abracadabra' if c not in 'abc'}``
+* Use the type constructor: ``set()``, ``set('foobar')``, ``set(['a', 'b', 'foo'])``
- Instances of :class:`set` and :class:`frozenset` provide the following
- operations:
+Instances of :class:`set` and :class:`frozenset` provide the following
+operations:
- .. describe:: len(s)
+.. describe:: len(s)
- Return the number of elements in set *s* (cardinality of *s*).
+ Return the number of elements in set *s* (cardinality of *s*).
- .. describe:: x in s
+.. describe:: x in s
- Test *x* for membership in *s*.
+ Test *x* for membership in *s*.
- .. describe:: x not in s
+.. describe:: x not in s
- Test *x* for non-membership in *s*.
+ Test *x* for non-membership in *s*.
- .. method:: isdisjoint(other)
+.. method:: frozenset.isdisjoint(other, /)
+ set.isdisjoint(other, /)
- Return ``True`` if the set has no elements in common with *other*. Sets are
- disjoint if and only if their intersection is the empty set.
+ Return ``True`` if the set has no elements in common with *other*. Sets are
+ disjoint if and only if their intersection is the empty set.
- .. method:: issubset(other)
- set <= other
+.. method:: frozenset.issubset(other, /)
+ set.issubset(other, /)
+.. describe:: set <= other
- Test whether every element in the set is in *other*.
+ Test whether every element in the set is in *other*.
- .. method:: set < other
+.. describe:: set < other
- Test whether the set is a proper subset of *other*, that is,
- ``set <= other and set != other``.
+ Test whether the set is a proper subset of *other*, that is,
+ ``set <= other and set != other``.
- .. method:: issuperset(other)
- set >= other
+.. method:: frozenset.issuperset(other, /)
+ set.issuperset(other, /)
+.. describe:: set >= other
- Test whether every element in *other* is in the set.
+ Test whether every element in *other* is in the set.
- .. method:: set > other
+.. describe:: set > other
- Test whether the set is a proper superset of *other*, that is, ``set >=
- other and set != other``.
+ Test whether the set is a proper superset of *other*, that is, ``set >=
+ other and set != other``.
- .. method:: union(*others)
- set | other | ...
+.. method:: frozenset.union(*others)
+ set.union(*others)
+.. describe:: set | other | ...
- Return a new set with elements from the set and all others.
+ Return a new set with elements from the set and all others.
- .. method:: intersection(*others)
- set & other & ...
+.. method:: frozenset.intersection(*others)
+ set.intersection(*others)
+.. describe:: set & other & ...
- Return a new set with elements common to the set and all others.
+ Return a new set with elements common to the set and all others.
- .. method:: difference(*others)
- set - other - ...
+.. method:: frozenset.difference(*others)
+ set.difference(*others)
+.. describe:: set - other - ...
- Return a new set with elements in the set that are not in the others.
+ Return a new set with elements in the set that are not in the others.
- .. method:: symmetric_difference(other)
- set ^ other
+.. method:: frozenset.symmetric_difference(other, /)
+ set.symmetric_difference(other, /)
+.. describe:: set ^ other
- Return a new set with elements in either the set or *other* but not both.
+ Return a new set with elements in either the set or *other* but not both.
- .. method:: copy()
+.. method:: frozenset.copy()
+ set.copy()
- Return a shallow copy of the set.
+ Return a shallow copy of the set.
- Note, the non-operator versions of :meth:`union`, :meth:`intersection`,
- :meth:`difference`, :meth:`symmetric_difference`, :meth:`issubset`, and
- :meth:`issuperset` methods will accept any iterable as an argument. In
- contrast, their operator based counterparts require their arguments to be
- sets. This precludes error-prone constructions like ``set('abc') & 'cbs'``
- in favor of the more readable ``set('abc').intersection('cbs')``.
+Note, the non-operator versions of :meth:`~frozenset.union`,
+:meth:`~frozenset.intersection`, :meth:`~frozenset.difference`, :meth:`~frozenset.symmetric_difference`, :meth:`~frozenset.issubset`, and
+:meth:`~frozenset.issuperset` methods will accept any iterable as an argument. In
+contrast, their operator based counterparts require their arguments to be
+sets. This precludes error-prone constructions like ``set('abc') & 'cbs'``
+in favor of the more readable ``set('abc').intersection('cbs')``.
- Both :class:`set` and :class:`frozenset` support set to set comparisons. Two
- sets are equal if and only if every element of each set is contained in the
- other (each is a subset of the other). A set is less than another set if and
- only if the first set is a proper subset of the second set (is a subset, but
- is not equal). A set is greater than another set if and only if the first set
- is a proper superset of the second set (is a superset, but is not equal).
+Both :class:`set` and :class:`frozenset` support set to set comparisons. Two
+sets are equal if and only if every element of each set is contained in the
+other (each is a subset of the other). A set is less than another set if and
+only if the first set is a proper subset of the second set (is a subset, but
+is not equal). A set is greater than another set if and only if the first set
+is a proper superset of the second set (is a superset, but is not equal).
- Instances of :class:`set` are compared to instances of :class:`frozenset`
- based on their members. For example, ``set('abc') == frozenset('abc')``
- returns ``True`` and so does ``set('abc') in set([frozenset('abc')])``.
+Instances of :class:`set` are compared to instances of :class:`frozenset`
+based on their members. For example, ``set('abc') == frozenset('abc')``
+returns ``True`` and so does ``set('abc') in set([frozenset('abc')])``.
- The subset and equality comparisons do not generalize to a total ordering
- function. For example, any two nonempty disjoint sets are not equal and are not
- subsets of each other, so *all* of the following return ``False``: ``ab``.
+The subset and equality comparisons do not generalize to a total ordering
+function. For example, any two nonempty disjoint sets are not equal and are not
+subsets of each other, so *all* of the following return ``False``: ``ab``.
- Since sets only define partial ordering (subset relationships), the output of
- the :meth:`list.sort` method is undefined for lists of sets.
+Since sets only define partial ordering (subset relationships), the output of
+the :meth:`list.sort` method is undefined for lists of sets.
- Set elements, like dictionary keys, must be :term:`hashable`.
+Set elements, like dictionary keys, must be :term:`hashable`.
- Binary operations that mix :class:`set` instances with :class:`frozenset`
- return the type of the first operand. For example: ``frozenset('ab') |
- set('bc')`` returns an instance of :class:`frozenset`.
+Binary operations that mix :class:`set` instances with :class:`frozenset`
+return the type of the first operand. For example: ``frozenset('ab') |
+set('bc')`` returns an instance of :class:`frozenset`.
- The following table lists operations available for :class:`set` that do not
- apply to immutable instances of :class:`frozenset`:
+The following table lists operations available for :class:`set` that do not
+apply to immutable instances of :class:`frozenset`:
- .. method:: update(*others)
- set |= other | ...
+.. method:: set.update(*others)
+.. describe:: set |= other | ...
- Update the set, adding elements from all others.
+ Update the set, adding elements from all others.
- .. method:: intersection_update(*others)
- set &= other & ...
+.. method:: set.intersection_update(*others)
+.. describe:: set &= other & ...
- Update the set, keeping only elements found in it and all others.
+ Update the set, keeping only elements found in it and all others.
- .. method:: difference_update(*others)
- set -= other | ...
+.. method:: set.difference_update(*others)
+.. describe:: set -= other | ...
- Update the set, removing elements found in others.
+ Update the set, removing elements found in others.
- .. method:: symmetric_difference_update(other)
- set ^= other
+.. method:: set.symmetric_difference_update(other, /)
+.. describe:: set ^= other
- Update the set, keeping only elements found in either set, but not in both.
+ Update the set, keeping only elements found in either set, but not in both.
- .. method:: add(elem)
+.. method:: set.add(elem, /)
- Add element *elem* to the set.
+ Add element *elem* to the set.
- .. method:: remove(elem)
+.. method:: set.remove(elem, /)
- Remove element *elem* from the set. Raises :exc:`KeyError` if *elem* is
- not contained in the set.
+ Remove element *elem* from the set. Raises :exc:`KeyError` if *elem* is
+ not contained in the set.
- .. method:: discard(elem)
+.. method:: set.discard(elem, /)
- Remove element *elem* from the set if it is present.
+ Remove element *elem* from the set if it is present.
- .. method:: pop()
+.. method:: set.pop()
- Remove and return an arbitrary element from the set. Raises
- :exc:`KeyError` if the set is empty.
+ Remove and return an arbitrary element from the set. Raises
+ :exc:`KeyError` if the set is empty.
- .. method:: clear()
+.. method:: set.clear()
- Remove all elements from the set.
+ Remove all elements from the set.
- Note, the non-operator versions of the :meth:`update`,
- :meth:`intersection_update`, :meth:`difference_update`, and
- :meth:`symmetric_difference_update` methods will accept any iterable as an
- argument.
+Note, the non-operator versions of the :meth:`~set.update`,
+:meth:`~set.intersection_update`, :meth:`~set.difference_update`, and
+:meth:`~set.symmetric_difference_update` methods will accept any iterable as an
+argument.
- Note, the *elem* argument to the :meth:`~object.__contains__`,
- :meth:`remove`, and
- :meth:`discard` methods may be a set. To support searching for an equivalent
- frozenset, a temporary one is created from *elem*.
+Note, the *elem* argument to the :meth:`~object.__contains__`,
+:meth:`~set.remove`, and
+:meth:`~set.discard` methods may be a set. To support searching for an equivalent
+frozenset, a temporary one is created from *elem*.
+Sets and frozensets are :ref:`generic ` over the type of their elements.
.. _typesmapping:
@@ -4449,8 +5057,8 @@ Values that compare equal (such as ``1``, ``1.0``, and ``True``)
can be used interchangeably to index the same dictionary entry.
.. class:: dict(**kwargs)
- dict(mapping, **kwargs)
- dict(iterable, **kwargs)
+ dict(mapping, /, **kwargs)
+ dict(iterable, /, **kwargs)
Return a new dictionary initialized from an optional positional argument
and a possibly empty set of keyword arguments.
@@ -4464,21 +5072,24 @@ can be used interchangeably to index the same dictionary entry.
``dict([('foo', 100), ('bar', 200)])``, ``dict(foo=100, bar=200)``
If no positional argument is given, an empty dictionary is created.
- If a positional argument is given and it is a mapping object, a dictionary
- is created with the same key-value pairs as the mapping object. Otherwise,
- the positional argument must be an :term:`iterable` object. Each item in
- the iterable must itself be an iterable with exactly two objects. The
- first object of each item becomes a key in the new dictionary, and the
- second object the corresponding value. If a key occurs more than once, the
- last value for that key becomes the corresponding value in the new
- dictionary.
+ If a positional argument is given and it defines a ``keys()`` method, a
+ dictionary is created by calling :meth:`~object.__getitem__` on the argument with
+ each returned key from the method. Otherwise, the positional argument must be an
+ :term:`iterable` object. Each item in the iterable must itself be an iterable
+ with exactly two elements. The first element of each item becomes a key in the
+ new dictionary, and the second element the corresponding value. If a key occurs
+ more than once, the last value for that key becomes the corresponding value in
+ the new dictionary.
If keyword arguments are given, the keyword arguments and their values are
added to the dictionary created from the positional argument. If a key
being added is already present, the value from the keyword argument
replaces the value from the positional argument.
- To illustrate, the following examples all return a dictionary equal to
+ Dictionaries compare equal if and only if they have the same ``(key,
+ value)`` pairs (regardless of ordering). Order comparisons ('<', '<=', '>=', '>') raise
+ :exc:`TypeError`. To illustrate dictionary creation and equality,
+ the following examples all return a dictionary equal to
``{"one": 1, "two": 2, "three": 3}``::
>>> a = dict(one=1, two=2, three=3)
@@ -4493,6 +5104,30 @@ can be used interchangeably to index the same dictionary entry.
Providing keyword arguments as in the first example only works for keys that
are valid Python identifiers. Otherwise, any valid keys can be used.
+ Dictionaries preserve insertion order. Note that updating a key does not
+ affect the order. Keys added after deletion are inserted at the end. ::
+
+ >>> d = {"one": 1, "two": 2, "three": 3, "four": 4}
+ >>> d
+ {'one': 1, 'two': 2, 'three': 3, 'four': 4}
+ >>> list(d)
+ ['one', 'two', 'three', 'four']
+ >>> list(d.values())
+ [1, 2, 3, 4]
+ >>> d["one"] = 42
+ >>> d
+ {'one': 42, 'two': 2, 'three': 3, 'four': 4}
+ >>> del d["two"]
+ >>> d["two"] = None
+ >>> d
+ {'one': 42, 'three': 3, 'four': 4, 'two': None}
+
+ .. versionchanged:: 3.7
+ Dictionary order is guaranteed to be insertion order. This behavior was
+ an implementation detail of CPython from 3.6.
+
+ Dictionaries are :ref:`generic ` over two types, signifying
+ (respectively) the types of the dictionary's keys and values.
These are the operations that dictionaries support (and therefore, custom
mapping types should support too):
@@ -4512,13 +5147,13 @@ can be used interchangeably to index the same dictionary entry.
.. index:: __missing__()
- If a subclass of dict defines a method :meth:`__missing__` and *key*
+ If a subclass of dict defines a method :meth:`~object.__missing__` and *key*
is not present, the ``d[key]`` operation calls that method with the key *key*
as argument. The ``d[key]`` operation then returns or raises whatever is
returned or raised by the ``__missing__(key)`` call.
- No other operations or methods invoke :meth:`__missing__`. If
- :meth:`__missing__` is not defined, :exc:`KeyError` is raised.
- :meth:`__missing__` must be a method; it cannot be an instance variable::
+ No other operations or methods invoke :meth:`~object.__missing__`. If
+ :meth:`~object.__missing__` is not defined, :exc:`KeyError` is raised.
+ :meth:`~object.__missing__` must be a method; it cannot be an instance variable::
>>> class Counter(dict):
... def __missing__(self, key):
@@ -4532,7 +5167,8 @@ can be used interchangeably to index the same dictionary entry.
1
The example above shows part of the implementation of
- :class:`collections.Counter`. A different ``__missing__`` method is used
+ :class:`collections.Counter`.
+ A different :meth:`!__missing__` method is used
by :class:`collections.defaultdict`.
.. describe:: d[key] = value
@@ -4565,7 +5201,7 @@ can be used interchangeably to index the same dictionary entry.
Return a shallow copy of the dictionary.
- .. classmethod:: fromkeys(iterable[, value])
+ .. classmethod:: fromkeys(iterable, value=None, /)
Create a new dictionary with keys from *iterable* and values set to *value*.
@@ -4575,7 +5211,7 @@ can be used interchangeably to index the same dictionary entry.
such as an empty list. To get distinct values, use a :ref:`dict
comprehension ` instead.
- .. method:: get(key[, default])
+ .. method:: get(key, default=None, /)
Return the value for *key* if *key* is in the dictionary, else *default*.
If *default* is not given, it defaults to ``None``, so that this method
@@ -4591,7 +5227,8 @@ can be used interchangeably to index the same dictionary entry.
Return a new view of the dictionary's keys. See the :ref:`documentation
of view objects `.
- .. method:: pop(key[, default])
+ .. method:: pop(key, /)
+ pop(key, default, /)
If *key* is in the dictionary, remove it and return its value, else return
*default*. If *default* is not given and *key* is not in the dictionary,
@@ -4617,21 +5254,24 @@ can be used interchangeably to index the same dictionary entry.
.. versionadded:: 3.8
- .. method:: setdefault(key[, default])
+ .. method:: setdefault(key, default=None, /)
If *key* is in the dictionary, return its value. If not, insert *key*
with a value of *default* and return *default*. *default* defaults to
``None``.
- .. method:: update([other])
+ .. method:: update(**kwargs)
+ update(mapping, /, **kwargs)
+ update(iterable, /, **kwargs)
- Update the dictionary with the key/value pairs from *other*, overwriting
+ Update the dictionary with the key/value pairs from *mapping* or *iterable* and *kwargs*, overwriting
existing keys. Return ``None``.
- :meth:`update` accepts either another dictionary object or an iterable of
- key/value pairs (as tuples or other iterables of length two). If keyword
- arguments are specified, the dictionary is then updated with those
- key/value pairs: ``d.update(red=1, blue=2)``.
+ :meth:`update` accepts either another object with a ``keys()`` method (in
+ which case :meth:`~object.__getitem__` is called with every key returned from
+ the method) or an iterable of key/value pairs (as tuples or other iterables
+ of length two). If keyword arguments are specified, the dictionary is then
+ updated with those key/value pairs: ``d.update(red=1, blue=2)``.
.. method:: values()
@@ -4662,32 +5302,6 @@ can be used interchangeably to index the same dictionary entry.
.. versionadded:: 3.9
- Dictionaries compare equal if and only if they have the same ``(key,
- value)`` pairs (regardless of ordering). Order comparisons ('<', '<=', '>=', '>') raise
- :exc:`TypeError`.
-
- Dictionaries preserve insertion order. Note that updating a key does not
- affect the order. Keys added after deletion are inserted at the end. ::
-
- >>> d = {"one": 1, "two": 2, "three": 3, "four": 4}
- >>> d
- {'one': 1, 'two': 2, 'three': 3, 'four': 4}
- >>> list(d)
- ['one', 'two', 'three', 'four']
- >>> list(d.values())
- [1, 2, 3, 4]
- >>> d["one"] = 42
- >>> d
- {'one': 42, 'two': 2, 'three': 3, 'four': 4}
- >>> del d["two"]
- >>> d["two"] = None
- >>> d
- {'one': 42, 'three': 3, 'four': 4, 'two': None}
-
- .. versionchanged:: 3.7
- Dictionary order is guaranteed to be insertion order. This behavior was
- an implementation detail of CPython from 3.6.
-
Dictionaries and dictionary views are reversible. ::
>>> d = {"one": 1, "two": 2, "three": 3, "four": 4}
@@ -4860,9 +5474,11 @@ before the statement body is executed and exited when the statement ends:
Returning a true value from this method will cause the :keyword:`with` statement
to suppress the exception and continue execution with the statement immediately
following the :keyword:`!with` statement. Otherwise the exception continues
- propagating after this method has finished executing. Exceptions that occur
- during execution of this method will replace any exception that occurred in the
- body of the :keyword:`!with` statement.
+ propagating after this method has finished executing.
+
+ If this method raises an exception while handling an earlier exception from the
+ :keyword:`with` block, the new exception is raised, and the original exception
+ is stored in its :attr:`~BaseException.__context__` attribute.
The exception passed in should never be reraised explicitly - instead, this
method should return a false value to indicate that the method completed
@@ -4951,7 +5567,8 @@ type and the :class:`bytes` data type:
``GenericAlias`` objects are instances of the class
:class:`types.GenericAlias`, which can also be used to create ``GenericAlias``
-objects directly.
+objects directly. Specializations of user-defined :ref:`generic classes `
+may not be instances of :class:`types.GenericAlias`, but they provide similar functionality.
.. describe:: T[X, Y, ...]
@@ -5000,6 +5617,15 @@ creation::
>>> type(l)
+
+Instances of ``GenericAlias`` are not classes at runtime, even though they behave like classes (they can be instantiated and subclassed)::
+
+ >>> import inspect
+ >>> inspect.isclass(list[int])
+ False
+
+This is true for :ref:`user-defined generics ` also.
+
Calling :func:`repr` or :func:`str` on a generic shows the parameterized type::
>>> repr(list[int])
@@ -5038,6 +5664,8 @@ list is non-exhaustive.
* :class:`set`
* :class:`frozenset`
* :class:`type`
+* :class:`asyncio.Future`
+* :class:`asyncio.Task`
* :class:`collections.deque`
* :class:`collections.defaultdict`
* :class:`collections.OrderedDict`
@@ -5181,7 +5809,7 @@ enables cleaner type hinting syntax compared to :data:`typing.Union`.
.. note::
- The ``|`` operand cannot be used at runtime to define unions where one or
+ The ``|`` operator cannot be used at runtime to define unions where one or
more members is a forward reference. For example, ``int | "Foo"``, where
``"Foo"`` is a reference to a class not yet defined, will fail at
runtime. For unions which include forward references, present the
@@ -5332,9 +5960,10 @@ Methods
.. index:: pair: object; method
-Methods are functions that are called using the attribute notation. There are
-two flavors: :ref:`built-in methods ` (such as :meth:`append`
-on lists) and :ref:`class instance method `.
+Methods are functions that are called using the attribute notation.
+There are two flavors: :ref:`built-in methods `
+(such as :meth:`~list.append` on lists)
+and :ref:`class instance methods `.
Built-in methods are described with the types that support them.
If you access a method (a function defined in a class namespace) through an
@@ -5440,13 +6069,34 @@ It is written as ``None``.
The Ellipsis Object
-------------------
-This object is commonly used by slicing (see :ref:`slicings`). It supports no
-special operations. There is exactly one ellipsis object, named
+This object is commonly used to indicate that something is omitted.
+It supports no special operations. There is exactly one ellipsis object, named
:const:`Ellipsis` (a built-in name). ``type(Ellipsis)()`` produces the
:const:`Ellipsis` singleton.
It is written as ``Ellipsis`` or ``...``.
+In typical use, ``...`` as the ``Ellipsis`` object appears in a few different
+places, for instance:
+
+- In type annotations, such as :ref:`callable arguments `
+ or :ref:`tuple elements `.
+
+- As the body of a function instead of a :ref:`pass statement `.
+
+- In third-party libraries, such as `Numpy's slicing and striding
+ `_.
+
+Python also uses three dots in ways that are not ``Ellipsis`` objects, for instance:
+
+- Doctest's :const:`ELLIPSIS `, as a pattern for missing content.
+
+- The default Python prompt of the :term:`interactive` shell when partial input is incomplete.
+
+Lastly, the Python documentation often uses three dots in conventional English
+usage to mean omitted content, even in code examples that also use them as the
+``Ellipsis``.
+
.. _bltin-notimplemented-object:
@@ -5481,22 +6131,6 @@ types, where they are relevant. Some of these are not reported by the
:func:`dir` built-in function.
-.. attribute:: object.__dict__
-
- A dictionary or other mapping object used to store an object's (writable)
- attributes.
-
-
-.. attribute:: instance.__class__
-
- The class to which a class instance belongs.
-
-
-.. attribute:: class.__bases__
-
- The tuple of base classes of a class object.
-
-
.. attribute:: definition.__name__
The name of the class, function, method, descriptor, or
@@ -5511,43 +6145,24 @@ types, where they are relevant. Some of these are not reported by the
.. versionadded:: 3.3
-.. attribute:: definition.__type_params__
-
- The :ref:`type parameters ` of generic classes, functions,
- and :ref:`type aliases `.
-
- .. versionadded:: 3.12
-
-
-.. attribute:: class.__mro__
-
- This attribute is a tuple of classes that are considered when looking for
- base classes during method resolution.
+.. attribute:: definition.__module__
+ The name of the module in which a class or function was defined.
-.. method:: class.mro()
- This method can be overridden by a metaclass to customize the method
- resolution order for its instances. It is called at class instantiation, and
- its result is stored in :attr:`~class.__mro__`.
+.. attribute:: definition.__doc__
+ The documentation string of a class or function, or ``None`` if undefined.
-.. method:: class.__subclasses__
-
- Each class keeps a list of weak references to its immediate subclasses. This
- method returns a list of all those references still alive. The list is in
- definition order. Example::
-
- >>> int.__subclasses__()
- [, , , ]
+.. attribute:: definition.__type_params__
-.. attribute:: class.__static_attributes__
+ The :ref:`type parameters ` of generic classes, functions,
+ and :ref:`type aliases `. For classes and functions that
+ are not generic, this will be an empty tuple.
- A tuple containing names of attributes of this class which are accessed
- through ``self.X`` from any function in its body.
+ .. versionadded:: 3.12
- .. versionadded:: 3.13
.. _int_max_str_digits:
diff --git a/Doc/c-api/allocation.rst b/Doc/c-api/allocation.rst
index b3609c233156b6e..40e1ffe3ed09952 100644
--- a/Doc/c-api/allocation.rst
+++ b/Doc/c-api/allocation.rst
@@ -2,7 +2,7 @@
.. _allocating-objects:
-Allocating Objects on the Heap
+Allocating objects on the heap
==============================
@@ -15,10 +15,8 @@ Allocating Objects on the Heap
.. c:function:: PyObject* PyObject_Init(PyObject *op, PyTypeObject *type)
Initialize a newly allocated object *op* with its type and initial
- reference. Returns the initialized object. If *type* indicates that the
- object participates in the cyclic garbage detector, it is added to the
- detector's set of observed objects. Other fields of the object are not
- affected.
+ reference. Returns the initialized object. Other fields of the object are
+ not affected.
.. c:function:: PyVarObject* PyObject_InitVar(PyVarObject *op, PyTypeObject *type, Py_ssize_t size)
@@ -37,6 +35,10 @@ Allocating Objects on the Heap
The size of the memory allocation is determined from the
:c:member:`~PyTypeObject.tp_basicsize` field of the type object.
+ Note that this function is unsuitable if *typeobj* has
+ :c:macro:`Py_TPFLAGS_HAVE_GC` set. For such objects,
+ use :c:func:`PyObject_GC_New` instead.
+
.. c:macro:: PyObject_NewVar(TYPE, typeobj, size)
@@ -51,14 +53,9 @@ Allocating Objects on the Heap
fields into the same allocation decreases the number of allocations,
improving the memory management efficiency.
-
-.. c:function:: void PyObject_Del(void *op)
-
- Releases memory allocated to an object using :c:macro:`PyObject_New` or
- :c:macro:`PyObject_NewVar`. This is normally called from the
- :c:member:`~PyTypeObject.tp_dealloc` handler specified in the object's type. The fields of
- the object should not be accessed after this call as the memory is no
- longer a valid Python object.
+ Note that this function is unsuitable if *typeobj* has
+ :c:macro:`Py_TPFLAGS_HAVE_GC` set. For such objects,
+ use :c:func:`PyObject_GC_NewVar` instead.
.. c:var:: PyObject _Py_NoneStruct
@@ -70,6 +67,40 @@ Allocating Objects on the Heap
.. seealso::
- :c:func:`PyModule_Create`
+ :ref:`moduleobjects`
To allocate and create extension modules.
+
+Soft-deprecated aliases
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. soft-deprecated:: 3.10
+
+These are aliases to existing functions and macros.
+They exist solely for backwards compatibility.
+
+
+.. list-table::
+ :widths: auto
+ :header-rows: 1
+
+ * * Soft-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`
diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst
index 834aae9372fe3bd..a3e76cadf5671c3 100644
--- a/Doc/c-api/arg.rst
+++ b/Doc/c-api/arg.rst
@@ -5,7 +5,7 @@
Parsing arguments and building values
=====================================
-These functions are useful when creating your own extensions functions and
+These functions are useful when creating your own extension functions and
methods. Additional information and examples are available in
:ref:`extending-index`.
@@ -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 have to call
+ The buffer may contain embedded null bytes. The caller has to call
:c:func:`PyBuffer_Release` when it is done with the buffer.
``es`` (:class:`str`) [const char \*encoding, char \*\*buffer]
@@ -229,12 +229,24 @@ There are three ways strings and buffers can be converted to C:
Numbers
-------
+These formats allow representing Python numbers or single characters as C numbers.
+Formats that require :class:`int`, :class:`float` or :class:`complex` can
+also use the corresponding special methods :meth:`~object.__index__`,
+:meth:`~object.__float__` or :meth:`~object.__complex__` to convert
+the Python object to the required type.
+
+For signed integer formats, :exc:`OverflowError` is raised if the value
+is out of range for the C type.
+For unsigned integer formats, no range checking is done --- the
+most significant bits are silently truncated when the receiving field is too
+small to receive the value.
+
``b`` (:class:`int`) [unsigned char]
- Convert a nonnegative Python integer to an unsigned tiny int, stored in a C
+ Convert a nonnegative Python integer to an unsigned tiny integer, stored in a C
:c:expr:`unsigned char`.
``B`` (:class:`int`) [unsigned char]
- Convert a Python integer to a tiny int without overflow checking, stored in a C
+ Convert a Python integer to a tiny integer without overflow checking, stored in a C
:c:expr:`unsigned char`.
``h`` (:class:`int`) [short int]
@@ -280,10 +292,10 @@ Numbers
length 1, to a C :c:expr:`int`.
``f`` (:class:`float`) [float]
- Convert a Python floating point number to a C :c:expr:`float`.
+ Convert a Python floating-point number to a C :c:expr:`float`.
``d`` (:class:`float`) [double]
- Convert a Python floating point number to a C :c:expr:`double`.
+ Convert a Python floating-point number to a C :c:expr:`double`.
``D`` (:class:`complex`) [Py_complex]
Convert a Python complex number to a C :c:type:`Py_complex` structure.
@@ -307,7 +319,7 @@ Other objects
.. _o_ampersand:
-``O&`` (object) [*converter*, *anything*]
+``O&`` (object) [*converter*, *address*]
Convert a Python object to a C variable through a *converter* function. This
takes two arguments: the first is a function, the second is the address of a C
variable (of arbitrary type), converted to :c:expr:`void *`. The *converter*
@@ -321,14 +333,20 @@ Other objects
the conversion has failed. When the conversion fails, the *converter* function
should raise an exception and leave the content of *address* unmodified.
- If the *converter* returns ``Py_CLEANUP_SUPPORTED``, it may get called a
+ .. c:macro:: Py_CLEANUP_SUPPORTED
+ :no-typesetting:
+
+ If the *converter* returns :c:macro:`!Py_CLEANUP_SUPPORTED`, it may get called a
second time if the argument parsing eventually fails, giving the converter a
chance to release any memory that it had already allocated. In this second
call, the *object* parameter will be ``NULL``; *address* will have the same value
as in the original call.
+ Examples of converters: :c:func:`PyUnicode_FSConverter` and
+ :c:func:`PyUnicode_FSDecoder`.
+
.. versionchanged:: 3.1
- ``Py_CLEANUP_SUPPORTED`` was added.
+ :c:macro:`!Py_CLEANUP_SUPPORTED` was added.
``p`` (:class:`bool`) [int]
Tests the value passed in for truth (a boolean **p**\ redicate) and converts
@@ -344,12 +362,6 @@ Other objects
in *items*. The C arguments must correspond to the individual format units in
*items*. Format units for sequences may be nested.
-It is possible to pass "long" integers (integers whose value exceeds the
-platform's :c:macro:`LONG_MAX`) however no proper range checking is done --- the
-most significant bits are silently truncated when the receiving field is too
-small to receive the value (actually, the semantics are inherited from downcasts
-in C --- your mileage may vary).
-
A few other characters have a meaning in a format string. These may not occur
inside nested parentheses. They are:
@@ -359,13 +371,18 @@ inside nested parentheses. They are:
their default value --- when an optional argument is not specified,
:c:func:`PyArg_ParseTuple` does not touch the contents of the corresponding C
variable(s).
+ For example, the format string ``"OO|OO"`` corresponds to the Python
+ signature ``f(a, b, c=None, d=None)``.
``$``
:c:func:`PyArg_ParseTupleAndKeywords` only:
Indicates that the remaining arguments in the Python argument list are
- keyword-only. Currently, all keyword-only arguments must also be optional
- arguments, so ``|`` must always be specified before ``$`` in the format
- string.
+ keyword-only.
+ They are optional if ``|`` was specified before ``$``, and required otherwise.
+ ``|`` cannot be specified after ``$``.
+ For example, the format string ``"O|O$O"`` corresponds to the Python
+ signature ``f(a, b=None, *, c=None)``,
+ and the format string ``"OO$OO"`` corresponds to ``f(a, b, *, c, d)``.
.. versionadded:: 3.3
@@ -627,6 +644,8 @@ Building values
``L`` (:class:`int`) [long long]
Convert a C :c:expr:`long long` to a Python integer object.
+ .. _capi-py-buildvalue-format-K:
+
``K`` (:class:`int`) [unsigned long long]
Convert a C :c:expr:`unsigned long long` to a Python integer object.
@@ -642,10 +661,10 @@ Building values
object of length 1.
``d`` (:class:`float`) [double]
- Convert a C :c:expr:`double` to a Python floating point number.
+ Convert a C :c:expr:`double` to a Python floating-point number.
``f`` (:class:`float`) [float]
- Convert a C :c:expr:`float` to a Python floating point number.
+ Convert a C :c:expr:`float` to a Python floating-point number.
``D`` (:class:`complex`) [Py_complex \*]
Convert a C :c:type:`Py_complex` structure to a Python complex number.
diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst
index 1e1cabdf242bd13..6bb72a2312be3bb 100644
--- a/Doc/c-api/buffer.rst
+++ b/Doc/c-api/buffer.rst
@@ -26,17 +26,19 @@ characteristic of being backed by a possibly large memory buffer. It is
then desirable, in some situations, to access that buffer directly and
without intermediate copying.
-Python provides such a facility at the C level in the form of the :ref:`buffer
-protocol `. This protocol has two sides:
+Python provides such a facility at the C and Python level in the form of the
+:ref:`buffer protocol `. This protocol has two sides:
.. index:: single: PyBufferProcs (C type)
- on the producer side, a type can export a "buffer interface" which allows
objects of that type to expose information about their underlying buffer.
- This interface is described in the section :ref:`buffer-structs`;
+ This interface is described in the section :ref:`buffer-structs`; for
+ Python see :ref:`python-buffer-protocol`.
- on the consumer side, several means are available to obtain a pointer to
- the raw underlying data of an object (for example a method parameter).
+ the raw underlying data of an object (for example a method parameter). For
+ Python see :class:`memoryview`.
Simple objects such as :class:`bytes` and :class:`bytearray` expose their
underlying buffer in byte-oriented form. Other forms are possible; for example,
@@ -62,6 +64,10 @@ In both cases, :c:func:`PyBuffer_Release` must be called when the buffer
isn't needed anymore. Failure to do so could lead to various issues such as
resource leaks.
+.. versionadded:: 3.12
+
+ The buffer protocol is now accessible in Python, see
+ :ref:`python-buffer-protocol` and :class:`memoryview`.
.. _buffer-structure:
@@ -147,9 +153,9 @@ a buffer, see :c:func:`PyObject_GetBuffer`.
or a :c:macro:`PyBUF_WRITABLE` request, the consumer must disregard
:c:member:`~Py_buffer.itemsize` and assume ``itemsize == 1``.
- .. c:member:: const char *format
+ .. c:member:: char *format
- A *NUL* terminated string in :mod:`struct` module style syntax describing
+ A *NULL* terminated string in :mod:`struct` module style syntax describing
the contents of a single item. If this is ``NULL``, ``"B"`` (unsigned bytes)
is assumed.
@@ -244,7 +250,6 @@ The following fields are not influenced by *flags* and must always be filled in
with the correct values: :c:member:`~Py_buffer.obj`, :c:member:`~Py_buffer.buf`,
:c:member:`~Py_buffer.len`, :c:member:`~Py_buffer.itemsize`, :c:member:`~Py_buffer.ndim`.
-
readonly, format
~~~~~~~~~~~~~~~~
@@ -253,7 +258,12 @@ readonly, format
Controls the :c:member:`~Py_buffer.readonly` field. If set, the exporter
MUST provide a writable buffer or else report failure. Otherwise, the
exporter MAY provide either a read-only or writable buffer, but the choice
- MUST be consistent for all consumers.
+ 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
@@ -265,8 +275,9 @@ readonly, format
Since :c:macro:`PyBUF_SIMPLE` is defined as 0, :c:macro:`PyBUF_WRITABLE`
can be used as a stand-alone flag to request a simple writable buffer.
-:c:macro:`PyBUF_FORMAT` can be \|'d to any of the flags except :c:macro:`PyBUF_SIMPLE`.
-The latter already implies format ``B`` (unsigned bytes).
+:c:macro:`PyBUF_FORMAT` must be \|'d to any of the flags except :c:macro:`PyBUF_SIMPLE`, because
+the latter already implies format ``B`` (unsigned bytes). :c:macro:`!PyBUF_FORMAT` cannot be
+used on its own.
shape, strides, suboffsets
diff --git a/Doc/c-api/bytearray.rst b/Doc/c-api/bytearray.rst
index 456f7d89bca03cd..ad7f97ddddb32a7 100644
--- a/Doc/c-api/bytearray.rst
+++ b/Doc/c-api/bytearray.rst
@@ -12,6 +12,12 @@ Byte Array Objects
This subtype of :c:type:`PyObject` represents a Python bytearray object.
+ .. impl-detail::
+
+ The internal buffer of :c:type:`PyByteArrayObject` always includes an
+ extra trailing null byte for compatibility with null terminated C
+ strings. This extra byte is not counted in :c:func:`PyByteArray_Size`
+ nor in the *len* arguments of the functions below.
.. c:var:: PyTypeObject PyByteArray_Type
@@ -42,17 +48,22 @@ Direct API functions
Return a new bytearray object from any object, *o*, that implements the
:ref:`buffer protocol `.
+ On failure, return ``NULL`` with an exception set.
+
.. c:function:: PyObject* PyByteArray_FromStringAndSize(const char *string, Py_ssize_t len)
- Create a new bytearray object from *string* and its length, *len*. On
- failure, ``NULL`` is returned.
+ Create a new bytearray object from *string* and its length, *len*.
+
+ On failure, return ``NULL`` with an exception set.
.. c:function:: PyObject* PyByteArray_Concat(PyObject *a, PyObject *b)
Concat bytearrays *a* and *b* and return a new bytearray with the result.
+ On failure, return ``NULL`` with an exception set.
+
.. c:function:: Py_ssize_t PyByteArray_Size(PyObject *bytearray)
diff --git a/Doc/c-api/bytes.rst b/Doc/c-api/bytes.rst
index bca78a9c369385a..d0aa04cd4f02581 100644
--- a/Doc/c-api/bytes.rst
+++ b/Doc/c-api/bytes.rst
@@ -8,6 +8,13 @@ Bytes Objects
These functions raise :exc:`TypeError` when expecting a bytes parameter and
called with a non-bytes parameter.
+.. impl-detail::
+
+ The internal buffer of :c:type:`PyBytesObject` always includes an extra
+ trailing null byte for compatibility with null terminated C strings.
+ This extra byte is not counted in :c:func:`PyBytes_Size` nor in the
+ various *length* and *size* arguments of the functions below.
+
.. index:: pair: object; bytes
@@ -176,10 +183,11 @@ called with a non-bytes parameter.
.. c:function:: void PyBytes_Concat(PyObject **bytes, PyObject *newpart)
Create a new bytes object in *\*bytes* containing the contents of *newpart*
- appended to *bytes*; the caller will own the new reference. The reference to
- the old value of *bytes* will be stolen. If the new object cannot be
- created, the old reference to *bytes* will still be discarded and the value
- of *\*bytes* will be set to ``NULL``; the appropriate exception will be set.
+ appended to *bytes*; the caller will own the new reference.
+ The reference to the old value of *bytes* will be ":term:`stolen `".
+ If the new object cannot be created, the old reference to *bytes* will still
+ be "stolen", the value of *\*bytes* will be set to ``NULL``, and
+ the appropriate exception will be set.
.. c:function:: void PyBytes_ConcatAndDel(PyObject **bytes, PyObject *newpart)
@@ -201,3 +209,38 @@ called with a non-bytes parameter.
reallocation fails, the original bytes object at *\*bytes* is deallocated,
*\*bytes* is set to ``NULL``, :exc:`MemoryError` is set, and ``-1`` is
returned.
+
+
+.. 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.
diff --git a/Doc/c-api/call.rst b/Doc/c-api/call.rst
index 7198d6bc056eb43..9838879a528934a 100644
--- a/Doc/c-api/call.rst
+++ b/Doc/c-api/call.rst
@@ -347,6 +347,8 @@ please see individual documentation for details.
.. versionadded:: 3.9
+.. c:function:: PyObject* _PyObject_Vectorcall(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+ :no-typesetting:
.. c:function:: PyObject* PyObject_Vectorcall(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)
@@ -358,7 +360,12 @@ please see individual documentation for details.
Return the result of the call on success, or raise an exception and return
*NULL* on failure.
- .. versionadded:: 3.9
+ .. versionadded:: 3.8 as ``_PyObject_Vectorcall``
+
+ .. versionchanged:: 3.9
+
+ Renamed to the current name, without the leading underscore.
+ The old provisional name is :term:`soft deprecated`.
.. c:function:: PyObject* PyObject_VectorcallDict(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwdict)
diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst
index cdb8aa33e9fd325..03a848d68ed7aba 100644
--- a/Doc/c-api/capsule.rst
+++ b/Doc/c-api/capsule.rst
@@ -15,13 +15,19 @@ 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 who need to pass an opaque value (as a :c:expr:`void*`
+ extension modules which 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::
@@ -105,9 +111,19 @@ Refer to :ref:`using-capsules` for more information on using these objects.
``module.attribute``. The *name* stored in the capsule must match this
string exactly.
+ This function splits *name* on the ``.`` character, and imports the first
+ element. It then processes further elements using attribute lookups.
+
Return the capsule's internal *pointer* on success. On failure, set an
exception and return ``NULL``.
+ .. note::
+
+ If *name* points to an attribute of some submodule or subpackage, this
+ submodule or subpackage must be previously imported using other means
+ (for example, by using :c:func:`PyImport_ImportModule`) for the
+ attribute lookups to succeed.
+
.. versionchanged:: 3.3
*no_block* has no effect anymore.
diff --git a/Doc/c-api/cell.rst b/Doc/c-api/cell.rst
index f8cd0344fdd1c0c..2501ed9580df898 100644
--- a/Doc/c-api/cell.rst
+++ b/Doc/c-api/cell.rst
@@ -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 contains a reference to
+variables of each stack frame that references the value contain 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
@@ -39,7 +39,8 @@ Cell objects are not likely to be useful elsewhere.
.. c:function:: PyObject* PyCell_Get(PyObject *cell)
- Return the contents of the cell *cell*.
+ Return the contents of the cell *cell*, which can be ``NULL``.
+ If *cell* is not a cell object, returns ``NULL`` with an exception set.
.. c:function:: PyObject* PyCell_GET(PyObject *cell)
@@ -52,8 +53,10 @@ Cell objects are not likely to be useful elsewhere.
Set the contents of the cell object *cell* to *value*. This releases the
reference to any current content of the cell. *value* may be ``NULL``. *cell*
- must be non-``NULL``; if it is not a cell object, ``-1`` will be returned. On
- success, ``0`` will be returned.
+ must be non-``NULL``.
+
+ On success, return ``0``.
+ If *cell* is not a cell object, set an exception and return ``-1``.
.. c:function:: void PyCell_SET(PyObject *cell, PyObject *value)
diff --git a/Doc/c-api/code.rst b/Doc/c-api/code.rst
index 968c472219c6431..c461ab936f6e69c 100644
--- a/Doc/c-api/code.rst
+++ b/Doc/c-api/code.rst
@@ -32,11 +32,13 @@ bound into a function.
.. c:function:: Py_ssize_t PyCode_GetNumFree(PyCodeObject *co)
- Return the number of free variables in a code object.
+ Return the number of :term:`free (closure) variables `
+ in a code object.
.. c:function:: int PyUnstable_Code_GetFirstFree(PyCodeObject *co)
- Return the position of the first free variable in a code object.
+ Return the position of the first :term:`free (closure) variable `
+ in a code object.
.. versionchanged:: 3.13
@@ -67,13 +69,14 @@ bound into a function.
The old name is deprecated, but will remain available until the
signature changes again.
+.. c:function:: PyCodeObject* PyCode_NewWithPosOnlyArgs(...)
+ :no-typesetting:
+
.. c:function:: PyCodeObject* PyUnstable_Code_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, PyObject *qualname, int firstlineno, PyObject *linetable, PyObject *exceptiontable)
Similar to :c:func:`PyUnstable_Code_New`, but with an extra "posonlyargcount" for positional-only arguments.
The same caveats that apply to ``PyUnstable_Code_New`` also apply to this function.
- .. index:: single: PyCode_NewWithPosOnlyArgs (C function)
-
.. versionadded:: 3.8 as ``PyCode_NewWithPosOnlyArgs``
.. versionchanged:: 3.11
@@ -96,8 +99,8 @@ bound into a function.
Return the line number of the instruction that occurs on or before ``byte_offset`` and ends after it.
If you just need the line number of a frame, use :c:func:`PyFrame_GetLineNumber` instead.
- For efficiently iterating over the line numbers in a code object, use `the API described in PEP 626
- `_.
+ For efficiently iterating over the line numbers in a code object, use :pep:`the API described in PEP 626
+ <0626#out-of-process-debuggers-and-profilers>`.
.. c:function:: int PyCode_Addr2Location(PyObject *co, int byte_offset, int *start_line, int *start_column, int *end_line, int *end_column)
@@ -144,7 +147,8 @@ bound into a function.
Equivalent to the Python code ``getattr(co, 'co_freevars')``.
Returns a new reference to a :c:type:`PyTupleObject` containing the names of
- the free variables. On error, ``NULL`` is returned and an exception is raised.
+ the :term:`free (closure) variables `. On error, ``NULL`` is returned
+ and an exception is raised.
.. versionadded:: 3.11
@@ -179,7 +183,7 @@ bound into a function.
Type of a code object watcher callback function.
If *event* is ``PY_CODE_EVENT_CREATE``, then the callback is invoked
- after `co` has been fully initialized. Otherwise, the callback is invoked
+ after *co* has been fully initialized. Otherwise, the callback is invoked
before the destruction of *co* takes place, so the prior state of *co*
can be inspected.
@@ -208,6 +212,78 @@ 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
+-----------------
+
+Code objects contain a bit-field of flags, which can be retrieved as the
+:attr:`~codeobject.co_flags` Python attribute (for example using
+:c:func:`PyObject_GetAttrString`), and set using a *flags* argument to
+:c:func:`PyUnstable_Code_New` and similar functions.
+
+Flags whose names start with ``CO_FUTURE_`` correspond to features normally
+selectable by :ref:`future statements `. These flags can be used in
+:c:member:`PyCompilerFlags.cf_flags`.
+Note that many ``CO_FUTURE_`` flags are mandatory in current versions of
+Python, and setting them has no effect.
+
+The following flags are available.
+For their meaning, see the linked documentation of their Python equivalents.
+
+
+.. list-table::
+ :widths: auto
+ :header-rows: 1
+
+ * * Flag
+ * Meaning
+ * * .. c:macro:: CO_OPTIMIZED
+ * :py:data:`inspect.CO_OPTIMIZED`
+ * * .. c:macro:: CO_NEWLOCALS
+ * :py:data:`inspect.CO_NEWLOCALS`
+ * * .. c:macro:: CO_VARARGS
+ * :py:data:`inspect.CO_VARARGS`
+ * * .. c:macro:: CO_VARKEYWORDS
+ * :py:data:`inspect.CO_VARKEYWORDS`
+ * * .. c:macro:: CO_NESTED
+ * :py:data:`inspect.CO_NESTED`
+ * * .. c:macro:: CO_GENERATOR
+ * :py:data:`inspect.CO_GENERATOR`
+ * * .. c:macro:: CO_COROUTINE
+ * :py:data:`inspect.CO_COROUTINE`
+ * * .. c:macro:: CO_ITERABLE_COROUTINE
+ * :py:data:`inspect.CO_ITERABLE_COROUTINE`
+ * * .. c:macro:: CO_ASYNC_GENERATOR
+ * :py:data:`inspect.CO_ASYNC_GENERATOR`
+
+ * * .. c:macro:: CO_FUTURE_DIVISION
+ * no effect (:py:data:`__future__.division`)
+ * * .. c:macro:: CO_FUTURE_ABSOLUTE_IMPORT
+ * no effect (:py:data:`__future__.absolute_import`)
+ * * .. c:macro:: CO_FUTURE_WITH_STATEMENT
+ * no effect (:py:data:`__future__.with_statement`)
+ * * .. c:macro:: CO_FUTURE_PRINT_FUNCTION
+ * no effect (:py:data:`__future__.print_function`)
+ * * .. c:macro:: CO_FUTURE_UNICODE_LITERALS
+ * no effect (:py:data:`__future__.unicode_literals`)
+ * * .. c:macro:: CO_FUTURE_GENERATOR_STOP
+ * no effect (:py:data:`__future__.generator_stop`)
+ * * .. c:macro:: CO_FUTURE_ANNOTATIONS
+ * :py:data:`__future__.annotations`
+
+
Extra information
-----------------
@@ -219,9 +295,12 @@ These functions are part of the unstable C API tier:
this functionality is a CPython implementation detail, and the API
may change without deprecation warnings.
+.. c:function:: Py_ssize_t _PyEval_RequestCodeExtraIndex(freefunc free)
+ :no-typesetting:
+
.. c:function:: Py_ssize_t PyUnstable_Eval_RequestCodeExtraIndex(freefunc free)
- Return a new an opaque index value used to adding data to code objects.
+ Return a new 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
@@ -231,8 +310,6 @@ may change without deprecation warnings.
*free* will be called on non-``NULL`` data stored under the new index.
Use :c:func:`Py_DecRef` when storing :c:type:`PyObject`.
- .. index:: single: _PyEval_RequestCodeExtraIndex (C function)
-
.. versionadded:: 3.6 as ``_PyEval_RequestCodeExtraIndex``
.. versionchanged:: 3.12
@@ -241,6 +318,9 @@ may change without deprecation warnings.
The old private name is deprecated, but will be available until the API
changes.
+.. c:function:: int _PyCode_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
+ :no-typesetting:
+
.. c:function:: int PyUnstable_Code_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
Set *extra* to the extra data stored under the given index.
@@ -249,8 +329,6 @@ may change without deprecation warnings.
If no data was set under the index, set *extra* to ``NULL`` and return
0 without setting an exception.
- .. index:: single: _PyCode_GetExtra (C function)
-
.. versionadded:: 3.6 as ``_PyCode_GetExtra``
.. versionchanged:: 3.12
@@ -259,13 +337,14 @@ may change without deprecation warnings.
The old private name is deprecated, but will be available until the API
changes.
+.. c:function:: int _PyCode_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
+ :no-typesetting:
+
.. c:function:: int PyUnstable_Code_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
Set the extra data stored under the given index to *extra*.
Return 0 on success. Set an exception and return -1 on failure.
- .. index:: single: _PyCode_SetExtra (C function)
-
.. versionadded:: 3.6 as ``_PyCode_SetExtra``
.. versionchanged:: 3.12
diff --git a/Doc/c-api/codec.rst b/Doc/c-api/codec.rst
index 8ae5c4fecd6248f..35ee048bd5fa9f5 100644
--- a/Doc/c-api/codec.rst
+++ b/Doc/c-api/codec.rst
@@ -7,7 +7,7 @@ Codec registry and support functions
Register a new codec search function.
- As side effect, this tries to load the :mod:`!encodings` package, if not yet
+ As a 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 encoder can be found.
+ :exc:`LookupError` if no decoder can be found.
Codec lookup API
@@ -129,3 +129,13 @@ 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
diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst
index 5a0474869071d94..67d0c5f144e0753 100644
--- a/Doc/c-api/complex.rst
+++ b/Doc/c-api/complex.rst
@@ -25,12 +25,16 @@ pointers. This is consistent throughout the API.
The C structure which corresponds to the value portion of a Python complex
number object. Most of the functions for dealing with complex number objects
- use structures of this type as input or output values, as appropriate. It is
- defined as::
+ use structures of this type as input or output values, as appropriate.
+
+ .. c:member:: double real
+ double imag
+
+ The structure is defined as::
typedef struct {
- double real;
- double imag;
+ double real;
+ double imag;
} Py_complex;
@@ -106,11 +110,13 @@ Complex Numbers as Python Objects
.. c:function:: PyObject* PyComplex_FromCComplex(Py_complex v)
Create a new Python complex number object from a C :c:type:`Py_complex` value.
+ Return ``NULL`` with an exception set on error.
.. c:function:: PyObject* PyComplex_FromDoubles(double real, double imag)
Return a new :c:type:`PyComplexObject` object from *real* and *imag*.
+ Return ``NULL`` with an exception set on error.
.. c:function:: double PyComplex_RealAsDouble(PyObject *op)
@@ -121,7 +127,9 @@ Complex Numbers as Python Objects
:meth:`~object.__complex__` method, this method will first be called to
convert *op* to a Python complex number object. If :meth:`!__complex__` is
not defined then it falls back to call :c:func:`PyFloat_AsDouble` and
- returns its result. Upon failure, this method returns ``-1.0``, so one
+ returns its result.
+
+ Upon failure, this method returns ``-1.0`` with an exception set, so one
should call :c:func:`PyErr_Occurred` to check for errors.
.. versionchanged:: 3.13
@@ -135,8 +143,10 @@ Complex Numbers as Python Objects
:meth:`~object.__complex__` method, this method will first be called to
convert *op* to a Python complex number object. If :meth:`!__complex__` is
not defined then it falls back to call :c:func:`PyFloat_AsDouble` and
- returns ``0.0`` on success. Upon failure, this method returns ``-1.0``, so
- one should call :c:func:`PyErr_Occurred` to check for errors.
+ returns ``0.0`` on success.
+
+ Upon failure, this method returns ``-1.0`` with an exception set, so one
+ should call :c:func:`PyErr_Occurred` to check for errors.
.. versionchanged:: 3.13
Use :meth:`~object.__complex__` if available.
@@ -149,8 +159,11 @@ Complex Numbers as Python Objects
method, this method will first be called to convert *op* to a Python complex
number object. If :meth:`!__complex__` is not defined then it falls back to
:meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back
- to :meth:`~object.__index__`. Upon failure, this method returns ``-1.0`` as a real
- value.
+ to :meth:`~object.__index__`.
+
+ Upon failure, this method returns :c:type:`Py_complex`
+ with :c:member:`~Py_complex.real` set to ``-1.0`` and with an exception set, so one
+ should call :c:func:`PyErr_Occurred` to check for errors.
.. versionchanged:: 3.8
Use :meth:`~object.__index__` if available.
diff --git a/Doc/c-api/concrete.rst b/Doc/c-api/concrete.rst
index 880f7b15ce68e82..1746fe95eaaca93 100644
--- a/Doc/c-api/concrete.rst
+++ b/Doc/c-api/concrete.rst
@@ -109,11 +109,20 @@ Other Objects
descriptor.rst
slice.rst
memoryview.rst
+ picklebuffer.rst
weakref.rst
capsule.rst
frame.rst
gen.rst
coro.rst
contextvars.rst
- datetime.rst
typehints.rst
+
+
+C API for extension modules
+===========================
+
+.. toctree::
+
+ curses.rst
+ datetime.rst
diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst
index 4aaf3905e81c8a6..f91ca221090febb 100644
--- a/Doc/c-api/conversion.rst
+++ b/Doc/c-api/conversion.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``, "something bad happened." ``str[size-1]`` is ``'\0'`` in
+* When ``rv < 0``, the output conversion failed and ``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.
@@ -128,22 +128,46 @@ 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 values ``Py_DTSF_SIGN``,
- ``Py_DTSF_ADD_DOT_0``, or ``Py_DTSF_ALT``, or-ed together:
+ *flags* can be zero or more of the following values or-ed together:
- * ``Py_DTSF_SIGN`` means to always precede the returned string with a sign
- character, even if *val* is non-negative.
+ .. c:namespace:: NULL
- * ``Py_DTSF_ADD_DOT_0`` means to ensure that the returned string will not look
- like an integer.
+ .. c:macro:: Py_DTSF_SIGN
- * ``Py_DTSF_ALT`` means to apply "alternate" formatting rules. See the
- documentation for the :c:func:`PyOS_snprintf` ``'#'`` specifier for
- details.
+ Always precede the returned string with a sign
+ character, even if *val* is non-negative.
- 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
- *val* is a finite number, an infinite number, or not a number, respectively.
+ .. 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
+
+ If *ptype* is non-``NULL``, then the value it points to will be set to one
+ of the following constants depending on the type of *val*:
+
+ .. list-table::
+ :header-rows: 1
+ :align: left
+
+ * - *\*ptype*
+ - type of *val*
+ * - .. c:macro:: Py_DTST_FINITE
+ - finite number
+ * - .. c:macro:: Py_DTST_INFINITE
+ - infinite number
+ * - .. c:macro:: Py_DTST_NAN
+ - not a number
The return value is a pointer to *buffer* with the converted string or
``NULL`` if the conversion failed. The caller is responsible for freeing the
@@ -152,13 +176,85 @@ The following functions provide locale-independent string to number conversions.
.. versionadded:: 3.1
-.. c:function:: int PyOS_stricmp(const char *s1, const char *s2)
+.. c:function:: int PyOS_mystricmp(const char *str1, const char *str2)
+ int PyOS_mystrnicmp(const char *str1, const char *str2, Py_ssize_t size)
+
+ 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.
+
+
+.. c:function:: int PyOS_stricmp(const char *str1, const char *str2)
+ int PyOS_strnicmp(const char *str1, const char *str2, 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)
- Case insensitive comparison of strings. The function works almost
- identically to :c:func:`!strcmp` except that it ignores the case.
+ Return the lowercase equivalent of the character *c*.
-.. c:function:: int PyOS_strnicmp(const char *s1, const char *s2, Py_ssize_t size)
+.. c:macro:: Py_TOUPPER(c)
- Case insensitive comparison of strings. The function works almost
- identically to :c:func:`!strncmp` except that it ignores the case.
+ Return the uppercase equivalent of the character *c*.
diff --git a/Doc/c-api/curses.rst b/Doc/c-api/curses.rst
new file mode 100644
index 000000000000000..5a1697c43cc969d
--- /dev/null
+++ b/Doc/c-api/curses.rst
@@ -0,0 +1,138 @@
+.. 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 ` 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.
+
diff --git a/Doc/c-api/datetime.rst b/Doc/c-api/datetime.rst
index 97522da773477e8..127d7c9c91a3d5f 100644
--- a/Doc/c-api/datetime.rst
+++ b/Doc/c-api/datetime.rst
@@ -8,11 +8,42 @@ 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.
@@ -46,7 +77,7 @@ macros.
.. c:var:: PyTypeObject PyDateTime_DeltaType
- This instance of :c:type:`PyTypeObject` represents Python type for
+ This instance of :c:type:`PyTypeObject` represents the Python type for
the difference between two datetime values;
it is the same object as :class:`datetime.timedelta` in the Python layer.
@@ -318,10 +349,23 @@ Macros for the convenience of modules implementing the DB API:
.. c:function:: PyObject* PyDateTime_FromTimestamp(PyObject *args)
Create and return a new :class:`datetime.datetime` object given an argument
- tuple suitable for passing to :meth:`datetime.datetime.fromtimestamp()`.
+ tuple suitable for passing to :meth:`datetime.datetime.fromtimestamp`.
.. c:function:: PyObject* PyDate_FromTimestamp(PyObject *args)
Create and return a new :class:`datetime.date` object given an argument
- tuple suitable for passing to :meth:`datetime.date.fromtimestamp()`.
+ 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.
diff --git a/Doc/c-api/descriptor.rst b/Doc/c-api/descriptor.rst
index b32c113e5f04573..813741f3eda51a5 100644
--- a/Doc/c-api/descriptor.rst
+++ b/Doc/c-api/descriptor.rst
@@ -8,8 +8,6 @@ Descriptor Objects
"Descriptors" are objects that describe some attribute of an object. They are
found in the dictionary of type objects.
-.. XXX document these!
-
.. c:var:: PyTypeObject PyProperty_Type
The type object for the built-in descriptor types.
@@ -17,24 +15,178 @@ found in the dictionary of type objects.
.. c:function:: PyObject* PyDescr_NewGetSet(PyTypeObject *type, struct PyGetSetDef *getset)
+ Create a new get-set descriptor for extension type *type* from the
+ :c:type:`PyGetSetDef` structure *getset*.
+
+ Get-set descriptors expose attributes implemented by C getter and setter
+ functions rather than stored directly in the instance. This is the same kind
+ of descriptor created for entries in :c:member:`~PyTypeObject.tp_getset`, and
+ it appears in Python as a :class:`types.GetSetDescriptorType` object.
+
+ On success, return a :term:`strong reference` to the descriptor. Return
+ ``NULL`` with an exception set on failure.
+
+.. c:function:: PyObject* PyDescr_NewMember(PyTypeObject *type, struct PyMemberDef *member)
+
+ Create a new member descriptor for extension type *type* from the
+ :c:type:`PyMemberDef` structure *member*.
+
+ Member descriptors expose fields in the type's C struct as Python
+ attributes. This is the same kind of descriptor created for entries in
+ :c:member:`~PyTypeObject.tp_members`, and it appears in Python as a
+ :class:`types.MemberDescriptorType` object.
+
+ On success, return a :term:`strong reference` to the descriptor. Return
+ ``NULL`` with an exception set on failure.
-.. c: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. They correspond to
+ :class:`types.GetSetDescriptorType` objects in Python.
.. c:function:: PyObject* PyDescr_NewMethod(PyTypeObject *type, struct PyMethodDef *meth)
+ Create a new method descriptor for extension type *type* from the
+ :c:type:`PyMethodDef` structure *meth*.
+
+ Method descriptors expose C functions as methods on a type. This is the same
+ kind of descriptor created for entries in
+ :c:member:`~PyTypeObject.tp_methods`, and it appears in Python as a
+ :class:`types.MethodDescriptorType` object.
+
+ On success, return a :term:`strong reference` to the descriptor. Return
+ ``NULL`` with an exception set on failure.
+
+.. c:var:: PyTypeObject PyMethodDescr_Type
+
+ The type object for method descriptor objects created from
+ :c:type:`PyMethodDef` structures. These descriptors expose C functions as
+ methods on a type, and correspond to :class:`types.MethodDescriptorType`
+ objects in Python.
+
+
+.. c:struct:: wrapperbase
+
+ Describes a slot wrapper used by :c:func:`PyDescr_NewWrapper`.
+
+ Each ``wrapperbase`` record stores the Python-visible name and metadata for a
+ special method implemented by a type slot, together with the wrapper
+ function used to adapt that slot to Python's calling convention.
+
+.. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
+
+ Create a new wrapper descriptor for extension type *type* from the
+ :c:struct:`wrapperbase` structure *base* and the wrapped slot function
+ pointer
+ *wrapped*.
+
+ Wrapper descriptors expose special methods implemented by type slots. This
+ is the same kind of descriptor that CPython creates for slot-based special
+ methods such as ``__repr__`` or ``__add__``, and it appears in Python as a
+ :class:`types.WrapperDescriptorType` object.
+
+ On success, return a :term:`strong reference` to the descriptor. Return
+ ``NULL`` with an exception set on failure.
+
+.. c:var:: PyTypeObject PyWrapperDescr_Type
-.. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *wrapper, void *wrapped)
+ 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)
+ Create a new class method descriptor for extension type *type* from the
+ :c:type:`PyMethodDef` structure *method*.
+
+ Class method descriptors expose C methods that receive the class rather than
+ an instance when accessed. This is the same kind of descriptor created for
+ ``METH_CLASS`` entries in :c:member:`~PyTypeObject.tp_methods`, and it
+ appears in Python as a :class:`types.ClassMethodDescriptorType` object.
+
+ On success, return a :term:`strong reference` to the descriptor. Return
+ ``NULL`` with an exception set on failure.
.. c:function:: int PyDescr_IsData(PyObject *descr)
- Return non-zero if the descriptor objects *descr* describes a data attribute, or
+ Return non-zero if the descriptor object *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 *)
+.. c:function:: PyObject* PyWrapper_New(PyObject *d, PyObject *self)
+
+ Create a new bound wrapper object from the wrapper descriptor *d* and the
+ instance *self*.
+
+ This is the bound form of a wrapper descriptor created by
+ :c:func:`PyDescr_NewWrapper`. CPython creates these objects when a slot
+ wrapper is accessed through an instance, and they appear in Python as
+ :class:`types.MethodWrapperType` objects.
+
+ On success, return a :term:`strong reference` to the wrapper object. Return
+ ``NULL`` with an exception set on failure.
+
+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 corresponds to
+ :class:`types.ClassMethodDescriptorType` objects 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.
diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst
index 03f3d28187bfe9a..88dcb1225f61788 100644
--- a/Doc/c-api/dict.rst
+++ b/Doc/c-api/dict.rst
@@ -43,6 +43,17 @@ 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.
@@ -50,7 +61,7 @@ Dictionary Objects
.. c:function:: int PyDict_Contains(PyObject *p, PyObject *key)
- Determine if dictionary *p* contains *key*. If an item in *p* is matches
+ Determine if dictionary *p* contains *key*. If an item in *p* matches
*key*, return ``1``, otherwise return ``0``. On error, return ``-1``.
This is equivalent to the Python expression ``key in p``.
@@ -73,8 +84,8 @@ Dictionary Objects
Insert *val* into the dictionary *p* with a key of *key*. *key* must be
:term:`hashable`; if it isn't, :exc:`TypeError` will be raised. Return
- ``0`` on success or ``-1`` on failure. This function *does not* steal a
- reference to *val*.
+ ``0`` on success or ``-1`` on failure.
+ This function *does not* ":term:`steal`" a reference to *val*.
.. c:function:: int PyDict_SetItemString(PyObject *p, const char *key, PyObject *val)
@@ -107,7 +118,7 @@ Dictionary Objects
* If the key is present, set *\*result* to a new :term:`strong reference`
to the value and return ``1``.
* If the key is missing, set *\*result* to ``NULL`` and return ``0``.
- * On error, raise an exception and return ``-1``.
+ * On error, raise an exception, set *\*result* to ``NULL`` and return ``-1``.
.. versionadded:: 3.13
@@ -156,7 +167,7 @@ Dictionary Objects
.. c:function:: int PyDict_GetItemStringRef(PyObject *p, const char *key, PyObject **result)
- Similar than :c:func:`PyDict_GetItemRef`, but *key* is specified as a
+ Similar to :c:func:`PyDict_GetItemRef`, but *key* is specified as a
:c:expr:`const char*` UTF-8 encoded bytes string, rather than a
:c:expr:`PyObject*`.
@@ -191,13 +202,14 @@ Dictionary Objects
to both *default_value* and *\*result* (if it's not ``NULL``).
These may refer to the same object: in that case you hold two separate
references to it.
+
.. versionadded:: 3.13
.. 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 missing.
+ Do not raise :exc:`KeyError` if the key is missing.
- If the key is present, set *\*result* to a new reference to the removed
value if *result* is not ``NULL``, and return ``1``.
@@ -205,8 +217,8 @@ Dictionary Objects
``NULL``, and return ``0``.
- On error, raise an exception and return ``-1``.
- This is similar to :meth:`dict.pop`, but without the default value and
- not raising :exc:`KeyError` if the key missing.
+ Similar to :meth:`dict.pop`, but without the default value and
+ not raising :exc:`KeyError` if the key is missing.
.. versionadded:: 3.13
@@ -244,6 +256,11 @@ 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
@@ -289,6 +306,17 @@ Dictionary Objects
Py_DECREF(o);
}
+ The function is not thread-safe in the :term:`free-threaded `
+ build without external synchronization. You can use
+ :c:macro:`Py_BEGIN_CRITICAL_SECTION` to lock the dictionary while iterating
+ over it::
+
+ Py_BEGIN_CRITICAL_SECTION(self->dict);
+ while (PyDict_Next(self->dict, &pos, &key, &value)) {
+ ...
+ }
+ Py_END_CRITICAL_SECTION();
+
.. c:function:: int PyDict_Merge(PyObject *a, PyObject *b, int override)
@@ -405,3 +433,138 @@ 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`
diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst
index 499bfb47cc4be54..ee5739b44c78e2d 100644
--- a/Doc/c-api/exceptions.rst
+++ b/Doc/c-api/exceptions.rst
@@ -34,7 +34,7 @@ propagated, additional calls into the Python/C API may not behave as intended
and may fail in mysterious ways.
.. note::
- The error indicator is **not** the result of :func:`sys.exc_info()`.
+ The error indicator is **not** the result of :func:`sys.exc_info`.
The former corresponds to an exception that is not yet caught (and is
therefore still propagating), while the latter returns an exception after
it is caught (and has therefore stopped propagating).
@@ -119,6 +119,21 @@ Printing and clearing
.. versionadded:: 3.12
+.. c:function:: void PyErr_Display(PyObject *unused, PyObject *value, PyObject *tb)
+
+ Legacy variant of :c:func:`PyErr_DisplayException`.
+
+ Print the exception *value* with its traceback to :data:`sys.stderr`.
+ If *value* has no traceback set, *tb* is used as its traceback.
+ The first argument is ignored.
+
+ If :data:`sys.stderr` is ``None``, nothing is printed.
+ If :data:`sys.stderr` is not set, the exception is dumped to the
+ C ``stderr`` stream instead.
+
+ .. deprecated:: 3.12
+ Use :c:func:`PyErr_DisplayException` instead.
+
Raising exceptions
==================
@@ -309,6 +324,14 @@ 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
@@ -331,6 +354,23 @@ 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
================
@@ -387,13 +427,22 @@ an error value).
.. c:function:: int PyErr_WarnFormat(PyObject *category, Py_ssize_t stack_level, const char *format, ...)
- Function similar to :c:func:`PyErr_WarnEx`, but use
+ Function similar to :c:func:`PyErr_WarnEx`, but uses
:c:func:`PyUnicode_FromFormat` to format the warning message. *format* is
an ASCII-encoded string.
.. 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
@@ -465,11 +514,12 @@ Querying the error indicator
.. c:function:: void PyErr_SetRaisedException(PyObject *exc)
Set *exc* as the exception currently being raised,
- clearing the existing exception if one is set.
+ clearing the existing exception if one is set. If *exc* is ``NULL``,
+ just clear the existing exception.
- .. warning::
+ *exc* must be a valid exception or ``NULL``.
- This call steals a reference to *exc*, which must be a valid exception.
+ This call ":term:`steals `" a reference to *exc*.
.. versionadded:: 3.12
@@ -607,7 +657,8 @@ Querying the error indicator
Set the exception info, as known from ``sys.exc_info()``. This refers
to an exception that was *already caught*, not to an exception that was
- freshly raised. This function steals the references of the arguments.
+ freshly raised. This function ":term:`steals `" the references
+ of the arguments.
To clear the exception state, pass ``NULL`` for all three arguments.
This function is kept for backwards compatibility. Prefer using
:c:func:`PyErr_SetHandledException`.
@@ -624,8 +675,8 @@ Querying the error indicator
.. versionchanged:: 3.11
The ``type`` and ``traceback`` arguments are no longer used and
can be NULL. The interpreter now derives them from the exception
- instance (the ``value`` argument). The function still steals
- references of all three arguments.
+ instance (the ``value`` argument). The function still
+ ":term:`steals `" references of all three arguments.
Signal Handling
@@ -639,28 +690,40 @@ Signal Handling
single: SIGINT (C macro)
single: KeyboardInterrupt (built-in exception)
- This function interacts with Python's signal handling.
+ Handle external interruptions, such as signals or activating a debugger,
+ whose processing has been delayed until it is safe
+ to run Python code and/or raise exceptions.
- If the function is called from the main thread and under the main Python
- interpreter, it checks whether a signal has been sent to the processes
- and if so, invokes the corresponding signal handler. If the :mod:`signal`
- module is supported, this can invoke a signal handler written in Python.
+ For example, pressing :kbd:`Ctrl-C` causes a terminal to send the
+ :py:data:`signal.SIGINT` signal.
+ This function executes the corresponding Python signal handler, which,
+ by default, raises the :exc:`KeyboardInterrupt` exception.
- The function attempts to handle all pending signals, and then returns ``0``.
- However, if a Python signal handler raises an exception, the error
- indicator is set and the function returns ``-1`` immediately (such that
- other pending signals may not have been handled yet: they will be on the
- next :c:func:`PyErr_CheckSignals()` invocation).
+ :c:func:`!PyErr_CheckSignals` should be called by long-running C code
+ frequently enough so that the response appears immediate to humans.
- If the function is called from a non-main thread, or under a non-main
- Python interpreter, it does nothing and returns ``0``.
+ Handlers invoked by this function currently include:
- This function can be called by long-running C code that wants to
- be interruptible by user requests (such as by pressing Ctrl-C).
+ - Signal handlers, including Python functions registered using
+ the :mod:`signal` module.
- .. note::
- The default Python signal handler for :c:macro:`!SIGINT` raises the
- :exc:`KeyboardInterrupt` exception.
+ Signal handlers are only run in the main thread of the main interpreter.
+
+ (This is where the function got the name: originally, signals
+ were the only way to interrupt the interpreter.)
+
+ - Running the garbage collector, if necessary.
+
+ If any handler raises an exception, immediately return ``-1`` with that
+ exception set.
+ Any remaining interruptions are left to be processed on the next
+ :c:func:`PyErr_CheckSignals()` invocation, if appropriate.
+
+ If all handlers finish successfully, or there are no handlers to run,
+ return ``0``.
+
+ .. versionchanged:: 3.12
+ This function may now invoke the garbage collector.
.. c:function:: void PyErr_SetInterrupt()
@@ -733,7 +796,7 @@ Exception Classes
This creates a class object derived from :exc:`Exception` (accessible in C as
:c:data:`PyExc_Exception`).
- The :attr:`!__module__` attribute of the new class is set to the first part (up
+ The :attr:`~type.__module__` attribute of the new class is set to the first part (up
to the last dot) of the *name* argument, and the class name is set to the last
part (after the last dot). The *base* argument can be used to specify alternate
base classes; it can either be only one class or a tuple of classes. The *dict*
@@ -749,9 +812,30 @@ Exception Classes
.. versionadded:: 3.2
+.. c:function:: int PyExceptionClass_Check(PyObject *ob)
+
+ Return non-zero if *ob* is an exception class, zero otherwise. This function always succeeds.
+
+
+.. c:function:: const char *PyExceptionClass_Name(PyObject *ob)
+
+ Return :c:member:`~PyTypeObject.tp_name` of the exception class *ob*.
+
+
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) `.
+
+
.. c:function:: PyObject* PyException_GetTraceback(PyObject *ex)
Return the traceback associated with the exception as a new reference, as
@@ -778,7 +862,7 @@ Exception Objects
Set the context associated with the exception to *ctx*. Use ``NULL`` to clear
it. There is no type check to make sure that *ctx* is an exception instance.
- This steals a reference to *ctx*.
+ This ":term:`steals `" a reference to *ctx*.
.. c:function:: PyObject* PyException_GetCause(PyObject *ex)
@@ -793,7 +877,8 @@ Exception Objects
Set the cause associated with the exception to *cause*. Use ``NULL`` to clear
it. There is no type check to make sure that *cause* is either an exception
- instance or ``None``. This steals a reference to *cause*.
+ instance or ``None``.
+ This ":term:`steals `" a reference to *cause*.
The :attr:`~BaseException.__suppress_context__` attribute is implicitly set
to ``True`` by this function.
@@ -932,7 +1017,7 @@ Properly implementing :c:member:`~PyTypeObject.tp_repr` for container types requ
special recursion handling. In addition to protecting the stack,
:c:member:`~PyTypeObject.tp_repr` also needs to track objects to prevent cycles. The
following two functions facilitate this functionality. Effectively,
-these are the C equivalent to :func:`reprlib.recursive_repr`.
+these are the C equivalent to :deco:`reprlib.recursive_repr`.
.. c:function:: int Py_ReprEnter(PyObject *object)
@@ -957,181 +1042,159 @@ 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 the
+ :term:`GIL`.
+
+ .. 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 the
+ :term:`GIL`.
+
+ .. seealso::
+ :py:func:`sys.setrecursionlimit`
.. _standardexceptions:
-Standard Exceptions
-===================
-
-All standard Python exceptions are available as global variables whose names are
-``PyExc_`` followed by the Python exception name. These have the type
-:c:expr:`PyObject*`; they are all class objects. For completeness, here are all
-the variables:
-
-.. index::
- single: PyExc_BaseException (C var)
- single: PyExc_Exception (C var)
- single: PyExc_ArithmeticError (C var)
- single: PyExc_AssertionError (C var)
- single: PyExc_AttributeError (C var)
- single: PyExc_BlockingIOError (C var)
- single: PyExc_BrokenPipeError (C var)
- single: PyExc_BufferError (C var)
- single: PyExc_ChildProcessError (C var)
- single: PyExc_ConnectionAbortedError (C var)
- single: PyExc_ConnectionError (C var)
- single: PyExc_ConnectionRefusedError (C var)
- single: PyExc_ConnectionResetError (C var)
- single: PyExc_EOFError (C var)
- single: PyExc_FileExistsError (C var)
- single: PyExc_FileNotFoundError (C var)
- single: PyExc_FloatingPointError (C var)
- single: PyExc_GeneratorExit (C var)
- single: PyExc_ImportError (C var)
- single: PyExc_IndentationError (C var)
- single: PyExc_IndexError (C var)
- single: PyExc_InterruptedError (C var)
- single: PyExc_IsADirectoryError (C var)
- single: PyExc_KeyError (C var)
- single: PyExc_KeyboardInterrupt (C var)
- single: PyExc_LookupError (C var)
- single: PyExc_MemoryError (C var)
- single: PyExc_ModuleNotFoundError (C var)
- single: PyExc_NameError (C var)
- single: PyExc_NotADirectoryError (C var)
- single: PyExc_NotImplementedError (C var)
- single: PyExc_OSError (C var)
- single: PyExc_OverflowError (C var)
- single: PyExc_PermissionError (C var)
- single: PyExc_ProcessLookupError (C var)
- single: PyExc_RecursionError (C var)
- single: PyExc_ReferenceError (C var)
- single: PyExc_RuntimeError (C var)
- single: PyExc_StopAsyncIteration (C var)
- single: PyExc_StopIteration (C var)
- single: PyExc_SyntaxError (C var)
- single: PyExc_SystemError (C var)
- single: PyExc_SystemExit (C var)
- single: PyExc_TabError (C var)
- single: PyExc_TimeoutError (C var)
- single: PyExc_TypeError (C var)
- single: PyExc_UnboundLocalError (C var)
- single: PyExc_UnicodeDecodeError (C var)
- single: PyExc_UnicodeEncodeError (C var)
- single: PyExc_UnicodeError (C var)
- single: PyExc_UnicodeTranslateError (C var)
- single: PyExc_ValueError (C var)
- single: PyExc_ZeroDivisionError (C var)
-
-+-----------------------------------------+---------------------------------+----------+
-| C Name | Python Name | Notes |
-+=========================================+=================================+==========+
-| :c:data:`PyExc_BaseException` | :exc:`BaseException` | [1]_ |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_Exception` | :exc:`Exception` | [1]_ |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ArithmeticError` | :exc:`ArithmeticError` | [1]_ |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_AssertionError` | :exc:`AssertionError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_AttributeError` | :exc:`AttributeError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_BlockingIOError` | :exc:`BlockingIOError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_BrokenPipeError` | :exc:`BrokenPipeError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_BufferError` | :exc:`BufferError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ChildProcessError` | :exc:`ChildProcessError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ConnectionAbortedError` | :exc:`ConnectionAbortedError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ConnectionError` | :exc:`ConnectionError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ConnectionRefusedError` | :exc:`ConnectionRefusedError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ConnectionResetError` | :exc:`ConnectionResetError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_EOFError` | :exc:`EOFError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_FileExistsError` | :exc:`FileExistsError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_FileNotFoundError` | :exc:`FileNotFoundError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_FloatingPointError` | :exc:`FloatingPointError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_GeneratorExit` | :exc:`GeneratorExit` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ImportError` | :exc:`ImportError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_IndentationError` | :exc:`IndentationError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_IndexError` | :exc:`IndexError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_InterruptedError` | :exc:`InterruptedError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_IsADirectoryError` | :exc:`IsADirectoryError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_KeyError` | :exc:`KeyError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_KeyboardInterrupt` | :exc:`KeyboardInterrupt` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_LookupError` | :exc:`LookupError` | [1]_ |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_MemoryError` | :exc:`MemoryError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ModuleNotFoundError` | :exc:`ModuleNotFoundError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_NameError` | :exc:`NameError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_NotADirectoryError` | :exc:`NotADirectoryError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_NotImplementedError` | :exc:`NotImplementedError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_OSError` | :exc:`OSError` | [1]_ |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_OverflowError` | :exc:`OverflowError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_PermissionError` | :exc:`PermissionError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ProcessLookupError` | :exc:`ProcessLookupError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_RecursionError` | :exc:`RecursionError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ReferenceError` | :exc:`ReferenceError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_RuntimeError` | :exc:`RuntimeError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_StopAsyncIteration` | :exc:`StopAsyncIteration` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_StopIteration` | :exc:`StopIteration` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_SyntaxError` | :exc:`SyntaxError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_SystemError` | :exc:`SystemError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_SystemExit` | :exc:`SystemExit` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_TabError` | :exc:`TabError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_TimeoutError` | :exc:`TimeoutError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_TypeError` | :exc:`TypeError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_UnboundLocalError` | :exc:`UnboundLocalError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_UnicodeDecodeError` | :exc:`UnicodeDecodeError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_UnicodeEncodeError` | :exc:`UnicodeEncodeError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_UnicodeError` | :exc:`UnicodeError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_UnicodeTranslateError` | :exc:`UnicodeTranslateError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ValueError` | :exc:`ValueError` | |
-+-----------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ZeroDivisionError` | :exc:`ZeroDivisionError` | |
-+-----------------------------------------+---------------------------------+----------+
+Exception and warning types
+===========================
+
+All standard Python exceptions and warning categories are available as global
+variables whose names are ``PyExc_`` followed by the Python exception name.
+These have the type :c:expr:`PyObject*`; they are all class objects.
+
+For completeness, here are all the variables:
+
+Exception types
+---------------
+
+.. list-table::
+ :align: left
+ :widths: auto
+ :header-rows: 1
+
+ * * C name
+ * Python name
+ * * .. c:var:: PyObject *PyExc_BaseException
+ * :exc:`BaseException`
+ * * .. c:var:: PyObject *PyExc_BaseExceptionGroup
+ * :exc:`BaseExceptionGroup`
+ * * .. c:var:: PyObject *PyExc_Exception
+ * :exc:`Exception`
+ * * .. c:var:: PyObject *PyExc_ArithmeticError
+ * :exc:`ArithmeticError`
+ * * .. c:var:: PyObject *PyExc_AssertionError
+ * :exc:`AssertionError`
+ * * .. c:var:: PyObject *PyExc_AttributeError
+ * :exc:`AttributeError`
+ * * .. c:var:: PyObject *PyExc_BlockingIOError
+ * :exc:`BlockingIOError`
+ * * .. c:var:: PyObject *PyExc_BrokenPipeError
+ * :exc:`BrokenPipeError`
+ * * .. c:var:: PyObject *PyExc_BufferError
+ * :exc:`BufferError`
+ * * .. c:var:: PyObject *PyExc_ChildProcessError
+ * :exc:`ChildProcessError`
+ * * .. c:var:: PyObject *PyExc_ConnectionAbortedError
+ * :exc:`ConnectionAbortedError`
+ * * .. c:var:: PyObject *PyExc_ConnectionError
+ * :exc:`ConnectionError`
+ * * .. c:var:: PyObject *PyExc_ConnectionRefusedError
+ * :exc:`ConnectionRefusedError`
+ * * .. c:var:: PyObject *PyExc_ConnectionResetError
+ * :exc:`ConnectionResetError`
+ * * .. c:var:: PyObject *PyExc_EOFError
+ * :exc:`EOFError`
+ * * .. c:var:: PyObject *PyExc_FileExistsError
+ * :exc:`FileExistsError`
+ * * .. c:var:: PyObject *PyExc_FileNotFoundError
+ * :exc:`FileNotFoundError`
+ * * .. c:var:: PyObject *PyExc_FloatingPointError
+ * :exc:`FloatingPointError`
+ * * .. c:var:: PyObject *PyExc_GeneratorExit
+ * :exc:`GeneratorExit`
+ * * .. c:var:: PyObject *PyExc_ImportError
+ * :exc:`ImportError`
+ * * .. c:var:: PyObject *PyExc_IndentationError
+ * :exc:`IndentationError`
+ * * .. c:var:: PyObject *PyExc_IndexError
+ * :exc:`IndexError`
+ * * .. c:var:: PyObject *PyExc_InterruptedError
+ * :exc:`InterruptedError`
+ * * .. c:var:: PyObject *PyExc_IsADirectoryError
+ * :exc:`IsADirectoryError`
+ * * .. c:var:: PyObject *PyExc_KeyError
+ * :exc:`KeyError`
+ * * .. c:var:: PyObject *PyExc_KeyboardInterrupt
+ * :exc:`KeyboardInterrupt`
+ * * .. c:var:: PyObject *PyExc_LookupError
+ * :exc:`LookupError`
+ * * .. c:var:: PyObject *PyExc_MemoryError
+ * :exc:`MemoryError`
+ * * .. c:var:: PyObject *PyExc_ModuleNotFoundError
+ * :exc:`ModuleNotFoundError`
+ * * .. c:var:: PyObject *PyExc_NameError
+ * :exc:`NameError`
+ * * .. c:var:: PyObject *PyExc_NotADirectoryError
+ * :exc:`NotADirectoryError`
+ * * .. c:var:: PyObject *PyExc_NotImplementedError
+ * :exc:`NotImplementedError`
+ * * .. c:var:: PyObject *PyExc_OSError
+ * :exc:`OSError`
+ * * .. c:var:: PyObject *PyExc_OverflowError
+ * :exc:`OverflowError`
+ * * .. c:var:: PyObject *PyExc_PermissionError
+ * :exc:`PermissionError`
+ * * .. c:var:: PyObject *PyExc_ProcessLookupError
+ * :exc:`ProcessLookupError`
+ * * .. c:var:: PyObject *PyExc_PythonFinalizationError
+ * :exc:`PythonFinalizationError`
+ * * .. c:var:: PyObject *PyExc_RecursionError
+ * :exc:`RecursionError`
+ * * .. c:var:: PyObject *PyExc_ReferenceError
+ * :exc:`ReferenceError`
+ * * .. c:var:: PyObject *PyExc_RuntimeError
+ * :exc:`RuntimeError`
+ * * .. c:var:: PyObject *PyExc_StopAsyncIteration
+ * :exc:`StopAsyncIteration`
+ * * .. c:var:: PyObject *PyExc_StopIteration
+ * :exc:`StopIteration`
+ * * .. c:var:: PyObject *PyExc_SyntaxError
+ * :exc:`SyntaxError`
+ * * .. c:var:: PyObject *PyExc_SystemError
+ * :exc:`SystemError`
+ * * .. c:var:: PyObject *PyExc_SystemExit
+ * :exc:`SystemExit`
+ * * .. c:var:: PyObject *PyExc_TabError
+ * :exc:`TabError`
+ * * .. c:var:: PyObject *PyExc_TimeoutError
+ * :exc:`TimeoutError`
+ * * .. c:var:: PyObject *PyExc_TypeError
+ * :exc:`TypeError`
+ * * .. c:var:: PyObject *PyExc_UnboundLocalError
+ * :exc:`UnboundLocalError`
+ * * .. c:var:: PyObject *PyExc_UnicodeDecodeError
+ * :exc:`UnicodeDecodeError`
+ * * .. c:var:: PyObject *PyExc_UnicodeEncodeError
+ * :exc:`UnicodeEncodeError`
+ * * .. c:var:: PyObject *PyExc_UnicodeError
+ * :exc:`UnicodeError`
+ * * .. c:var:: PyObject *PyExc_UnicodeTranslateError
+ * :exc:`UnicodeTranslateError`
+ * * .. c:var:: PyObject *PyExc_ValueError
+ * :exc:`ValueError`
+ * * .. c:var:: PyObject *PyExc_ZeroDivisionError
+ * :exc:`ZeroDivisionError`
.. versionadded:: 3.3
:c:data:`PyExc_BlockingIOError`, :c:data:`PyExc_BrokenPipeError`,
@@ -1149,88 +1212,116 @@ the variables:
.. versionadded:: 3.6
:c:data:`PyExc_ModuleNotFoundError`.
-These are compatibility aliases to :c:data:`PyExc_OSError`:
+.. versionadded:: 3.11
+ :c:data:`PyExc_BaseExceptionGroup`.
-.. index::
- single: PyExc_EnvironmentError (C var)
- single: PyExc_IOError (C var)
- single: PyExc_WindowsError (C var)
-+-------------------------------------+----------+
-| C Name | Notes |
-+=====================================+==========+
-| :c:data:`!PyExc_EnvironmentError` | |
-+-------------------------------------+----------+
-| :c:data:`!PyExc_IOError` | |
-+-------------------------------------+----------+
-| :c:data:`!PyExc_WindowsError` | [2]_ |
-+-------------------------------------+----------+
+OSError aliases
+---------------
+
+The following are a compatibility aliases to :c:data:`PyExc_OSError`.
.. versionchanged:: 3.3
These aliases used to be separate exception types.
+.. list-table::
+ :align: left
+ :widths: auto
+ :header-rows: 1
+
+ * * C name
+ * Python name
+ * Notes
+ * * .. c:var:: PyObject *PyExc_EnvironmentError
+ * :exc:`OSError`
+ *
+ * * .. c:var:: PyObject *PyExc_IOError
+ * :exc:`OSError`
+ *
+ * * .. c:var:: PyObject *PyExc_WindowsError
+ * :exc:`OSError`
+ * [win]_
+
Notes:
-.. [1]
- This is a base class for other standard exceptions.
+.. [win]
+ :c:var:`!PyExc_WindowsError` is only defined on Windows; protect code that
+ uses this by testing that the preprocessor macro ``MS_WINDOWS`` is defined.
-.. [2]
- Only defined on Windows; protect code that uses this by testing that the
- preprocessor macro ``MS_WINDOWS`` is defined.
.. _standardwarningcategories:
-Standard Warning Categories
-===========================
-
-All standard Python warning categories are available as global variables whose
-names are ``PyExc_`` followed by the Python exception name. These have the type
-:c:expr:`PyObject*`; they are all class objects. For completeness, here are all
-the variables:
-
-.. index::
- single: PyExc_Warning (C var)
- single: PyExc_BytesWarning (C var)
- single: PyExc_DeprecationWarning (C var)
- single: PyExc_FutureWarning (C var)
- single: PyExc_ImportWarning (C var)
- single: PyExc_PendingDeprecationWarning (C var)
- single: PyExc_ResourceWarning (C var)
- single: PyExc_RuntimeWarning (C var)
- single: PyExc_SyntaxWarning (C var)
- single: PyExc_UnicodeWarning (C var)
- single: PyExc_UserWarning (C var)
-
-+------------------------------------------+---------------------------------+----------+
-| C Name | Python Name | Notes |
-+==========================================+=================================+==========+
-| :c:data:`PyExc_Warning` | :exc:`Warning` | [3]_ |
-+------------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_BytesWarning` | :exc:`BytesWarning` | |
-+------------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_DeprecationWarning` | :exc:`DeprecationWarning` | |
-+------------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_FutureWarning` | :exc:`FutureWarning` | |
-+------------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ImportWarning` | :exc:`ImportWarning` | |
-+------------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_PendingDeprecationWarning`| :exc:`PendingDeprecationWarning`| |
-+------------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_ResourceWarning` | :exc:`ResourceWarning` | |
-+------------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_RuntimeWarning` | :exc:`RuntimeWarning` | |
-+------------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_SyntaxWarning` | :exc:`SyntaxWarning` | |
-+------------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_UnicodeWarning` | :exc:`UnicodeWarning` | |
-+------------------------------------------+---------------------------------+----------+
-| :c:data:`PyExc_UserWarning` | :exc:`UserWarning` | |
-+------------------------------------------+---------------------------------+----------+
+Warning types
+-------------
+
+.. list-table::
+ :align: left
+ :widths: auto
+ :header-rows: 1
+
+ * * C name
+ * Python name
+ * * .. c:var:: PyObject *PyExc_Warning
+ * :exc:`Warning`
+ * * .. c:var:: PyObject *PyExc_BytesWarning
+ * :exc:`BytesWarning`
+ * * .. c:var:: PyObject *PyExc_DeprecationWarning
+ * :exc:`DeprecationWarning`
+ * * .. c:var:: PyObject *PyExc_EncodingWarning
+ * :exc:`EncodingWarning`
+ * * .. c:var:: PyObject *PyExc_FutureWarning
+ * :exc:`FutureWarning`
+ * * .. c:var:: PyObject *PyExc_ImportWarning
+ * :exc:`ImportWarning`
+ * * .. c:var:: PyObject *PyExc_PendingDeprecationWarning
+ * :exc:`PendingDeprecationWarning`
+ * * .. c:var:: PyObject *PyExc_ResourceWarning
+ * :exc:`ResourceWarning`
+ * * .. c:var:: PyObject *PyExc_RuntimeWarning
+ * :exc:`RuntimeWarning`
+ * * .. c:var:: PyObject *PyExc_SyntaxWarning
+ * :exc:`SyntaxWarning`
+ * * .. c:var:: PyObject *PyExc_UnicodeWarning
+ * :exc:`UnicodeWarning`
+ * * .. c:var:: PyObject *PyExc_UserWarning
+ * :exc:`UserWarning`
.. versionadded:: 3.2
:c:data:`PyExc_ResourceWarning`.
-Notes:
+.. 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*.
-.. [3]
- This is a base class for other standard warning categories.
+ This function returns ``0`` on success, and returns ``-1`` with an
+ exception set on failure.
diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst
index e9019a0d500f7e5..1bb5c1b768510f4 100644
--- a/Doc/c-api/file.rst
+++ b/Doc/c-api/file.rst
@@ -93,6 +93,29 @@ 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)
@@ -100,9 +123,12 @@ the :mod:`io` APIs instead.
Write object *obj* to file object *p*. The only supported flag for *flags* is
:c:macro:`Py_PRINT_RAW`; if given, the :func:`str` of the object is written
- instead of the :func:`repr`. Return ``0`` on success or ``-1`` on failure; the
- appropriate exception will be set.
+ instead of the :func:`repr`.
+
+ If *obj* is ``NULL``, write the string ``""``.
+ Return ``0`` on success or ``-1`` on failure; the
+ appropriate exception will be set.
.. c:function:: int PyFile_WriteString(const char *s, PyObject *p)
diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst
index 4f6ac0d8175c6b2..5a2dc7ecc07db57 100644
--- a/Doc/c-api/float.rst
+++ b/Doc/c-api/float.rst
@@ -2,20 +2,20 @@
.. _floatobjects:
-Floating Point Objects
+Floating-Point Objects
======================
-.. index:: pair: object; floating point
+.. index:: pair: object; floating-point
.. c:type:: PyFloatObject
- This subtype of :c:type:`PyObject` represents a Python floating point object.
+ This subtype of :c:type:`PyObject` represents a Python floating-point object.
.. c:var:: PyTypeObject PyFloat_Type
- This instance of :c:type:`PyTypeObject` represents the Python floating point
+ This instance of :c:type:`PyTypeObject` represents the Python floating-point
type. This is the same object as :class:`float` in the Python layer.
@@ -45,7 +45,7 @@ Floating Point Objects
.. c:function:: double PyFloat_AsDouble(PyObject *pyfloat)
Return a C :c:expr:`double` representation of the contents of *pyfloat*. If
- *pyfloat* is not a Python floating point object but has a :meth:`~object.__float__`
+ *pyfloat* is not a Python floating-point object but has a :meth:`~object.__float__`
method, this method will first be called to convert *pyfloat* into a float.
If :meth:`!__float__` is not defined then it falls back to :meth:`~object.__index__`.
This method returns ``-1.0`` upon failure, so one should call
@@ -78,6 +78,104 @@ Floating Point Objects
Return the minimum normalized positive float *DBL_MIN* as C :c:expr:`double`.
+.. c:macro:: Py_INFINITY
+
+ This macro expands to a constant expression of type :c:expr:`double`, that
+ represents the positive infinity.
+
+ On most platforms, this is equivalent to the :c:macro:`!INFINITY` macro from
+ the C11 standard ```` header.
+
+
+.. c:macro:: Py_NAN
+
+ This macro expands to a constant expression of type :c:expr:`double`, that
+ represents a quiet not-a-number (qNaN) value.
+
+ On most platforms, this is equivalent to the :c:macro:`!NAN` macro from
+ the C11 standard ```` 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.
+
+
+.. 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.
+
+
+.. 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 ` 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
-------------------------
@@ -121,15 +219,15 @@ There are two problems on non-IEEE platforms:
* What this does is undefined if *x* is a NaN or infinity.
* ``-0.0`` and ``+0.0`` produce the same bytes string.
-.. c:function:: int PyFloat_Pack2(double x, unsigned char *p, int le)
+.. c:function:: int PyFloat_Pack2(double x, char *p, int le)
Pack a C double as the IEEE 754 binary16 half-precision format.
-.. c:function:: int PyFloat_Pack4(double x, unsigned char *p, int le)
+.. c:function:: int PyFloat_Pack4(double x, char *p, int le)
Pack a C double as the IEEE 754 binary32 single precision format.
-.. c:function:: int PyFloat_Pack8(double x, unsigned char *p, int le)
+.. c:function:: int PyFloat_Pack8(double x, char *p, int le)
Pack a C double as the IEEE 754 binary64 double precision format.
@@ -151,14 +249,14 @@ Return value: The unpacked double. On error, this is ``-1.0`` and
Note that on a non-IEEE platform this will refuse to unpack a bytes string that
represents a NaN or infinity.
-.. c:function:: double PyFloat_Unpack2(const unsigned char *p, int le)
+.. c:function:: double PyFloat_Unpack2(const char *p, int le)
Unpack the IEEE 754 binary16 half-precision format as a C double.
-.. c:function:: double PyFloat_Unpack4(const unsigned char *p, int le)
+.. c:function:: double PyFloat_Unpack4(const char *p, int le)
Unpack the IEEE 754 binary32 single precision format as a C double.
-.. c:function:: double PyFloat_Unpack8(const unsigned char *p, int le)
+.. c:function:: double PyFloat_Unpack8(const char *p, int le)
Unpack the IEEE 754 binary64 double precision format as a C double.
diff --git a/Doc/c-api/frame.rst b/Doc/c-api/frame.rst
index 82e0980ad753d00..70a610cea82d06a 100644
--- a/Doc/c-api/frame.rst
+++ b/Doc/c-api/frame.rst
@@ -1,6 +1,6 @@
.. highlight:: c
-Frame Objects
+Frame objects
-------------
.. c:type:: PyFrameObject
@@ -29,6 +29,12 @@ See also :ref:`Reflection `.
Previously, this type was only available after including
````.
+.. 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.
@@ -44,6 +50,7 @@ See also :ref:`Reflection `.
Return a :term:`strong reference`, or ``NULL`` if *frame* has no outer
frame.
+ This raises no exceptions.
.. versionadded:: 3.9
@@ -121,17 +128,18 @@ See also :ref:`Reflection `.
.. c:function:: PyObject* PyFrame_GetLocals(PyFrameObject *frame)
Get the *frame*'s :attr:`~frame.f_locals` attribute.
- If the frame refers to a function or comprehension, this returns
- a write-through proxy object that allows modifying the locals.
- In all other cases (classes, modules) it returns the :class:`dict`
- representing the frame locals directly.
+ If the frame refers to an :term:`optimized scope`, this returns a
+ write-through proxy object that allows modifying the locals.
+ In all other cases (classes, modules, :func:`exec`, :func:`eval`) it returns
+ the mapping representing the frame locals directly (as described for
+ :func:`locals`).
Return a :term:`strong reference`.
.. versionadded:: 3.11
.. versionchanged:: 3.13
- Return a proxy object for functions and comprehensions.
+ As part of :pep:`667`, return an instance of :c:var:`PyFrameLocalsProxy_Type`.
.. c:function:: int PyFrame_GetLineNumber(PyFrameObject *frame)
@@ -139,8 +147,73 @@ See also :ref:`Reflection `.
Return the line number that *frame* is currently executing.
+Frame locals proxies
+^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.13
+
+The :attr:`~frame.f_locals` attribute on a :ref:`frame object `
+is an instance of a "frame-locals proxy". The proxy object exposes a
+write-through view of the underlying locals dictionary for the frame. This
+ensures that the variables exposed by ``f_locals`` are always up to date with
+the live local variables in the frame itself.
+
+See :pep:`667` for more information.
+
+.. c:var:: PyTypeObject PyFrameLocalsProxy_Type
+
+ The type of frame :func:`locals` proxy objects.
+
+.. c:function:: int PyFrameLocalsProxy_Check(PyObject *obj)
+
+ 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)
+
+ 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.
+
+ .. soft-deprecated:: 3.13
+ This function now does nothing.
+
+
+.. c:function:: void PyFrame_FastToLocals(PyFrameObject *f)
+
+ 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.
-Internal Frames
+ .. soft-deprecated:: 3.13
+ This function now does nothing.
+
+
+.. c:function:: int PyFrame_FastToLocalsWithError(PyFrameObject *f)
+
+ 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.
+
+ .. soft-deprecated:: 3.13
+ This function now does nothing.
+
+
+.. seealso::
+ :pep:`667`
+
+
+Internal frames
^^^^^^^^^^^^^^^
Unless using :pep:`523`, you will not need this.
@@ -172,3 +245,39 @@ Unless using :pep:`523`, you will not need this.
.. versionadded:: 3.12
+.. c:var:: const PyTypeObject *PyUnstable_ExecutableKinds
+
+ An array of executable kinds (executor types) for frames, used for internal
+ debugging and tracing.
+
+ Tools like debuggers and profilers can use this to identify the type of execution
+ context associated with a frame (such as to filter out internal frames).
+ The entries are indexed by the following constants:
+
+ .. list-table::
+ :header-rows: 1
+ :widths: auto
+
+ * - Constant
+ - Description
+ * - .. c:macro:: PyUnstable_EXECUTABLE_KIND_SKIP
+ - The frame is internal (For example: inlined) and should be skipped by tools.
+ * - .. c:macro:: PyUnstable_EXECUTABLE_KIND_PY_FUNCTION
+ - The frame corresponds to a standard Python function.
+ * - .. c:macro:: PyUnstable_EXECUTABLE_KIND_BUILTIN_FUNCTION
+ - The frame corresponds to a function defined in native code.
+ * - .. c:macro:: PyUnstable_EXECUTABLE_KIND_METHOD_DESCRIPTOR
+ - The frame corresponds to a method on a class instance.
+
+ Note that reading the executable kind from a frame is currently only
+ possible with undocumented internal APIs.
+
+ .. versionadded:: 3.13
+
+
+.. c:macro:: PyUnstable_EXECUTABLE_KINDS
+
+ The number of entries in :c:data:`PyUnstable_ExecutableKinds`.
+
+ .. versionadded:: 3.13
+
diff --git a/Doc/c-api/function.rst b/Doc/c-api/function.rst
index e7fb5090c099339..7908e4f8561aebe 100644
--- a/Doc/c-api/function.rst
+++ b/Doc/c-api/function.rst
@@ -95,6 +95,22 @@ There are a few functions specific to Python functions.
.. versionadded:: 3.12
+
+.. c:function:: PyObject* PyFunction_GetKwDefaults(PyObject *op)
+
+ Return the keyword-only argument default values of the function object *op*. This can be a
+ 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``
@@ -123,6 +139,19 @@ There are a few functions specific to Python functions.
Raises :exc:`SystemError` and returns ``-1`` on failure.
+.. c:function:: PyObject *PyFunction_GET_CODE(PyObject *op)
+ PyObject *PyFunction_GET_GLOBALS(PyObject *op)
+ PyObject *PyFunction_GET_MODULE(PyObject *op)
+ PyObject *PyFunction_GET_DEFAULTS(PyObject *op)
+ PyObject *PyFunction_GET_KW_DEFAULTS(PyObject *op)
+ PyObject *PyFunction_GET_CLOSURE(PyObject *op)
+ PyObject *PyFunction_GET_ANNOTATIONS(PyObject *op)
+
+ These functions are similar to their ``PyFunction_Get*`` counterparts, but
+ do not do type checking. Passing anything other than an instance of
+ :c:data:`PyFunction_Type` is undefined behavior.
+
+
.. c:function:: int PyFunction_AddWatcher(PyFunction_WatchCallback callback)
Register *callback* as a function watcher for the current interpreter.
@@ -145,12 +174,13 @@ There are a few functions specific to Python functions.
.. c:type:: PyFunction_WatchEvent
- Enumeration of possible function watcher events:
- - ``PyFunction_EVENT_CREATE``
- - ``PyFunction_EVENT_DESTROY``
- - ``PyFunction_EVENT_MODIFY_CODE``
- - ``PyFunction_EVENT_MODIFY_DEFAULTS``
- - ``PyFunction_EVENT_MODIFY_KWDEFAULTS``
+ Enumeration of possible function watcher events:
+
+ - ``PyFunction_EVENT_CREATE``
+ - ``PyFunction_EVENT_DESTROY``
+ - ``PyFunction_EVENT_MODIFY_CODE``
+ - ``PyFunction_EVENT_MODIFY_DEFAULTS``
+ - ``PyFunction_EVENT_MODIFY_KWDEFAULTS``
.. versionadded:: 3.12
@@ -168,7 +198,7 @@ There are a few functions specific to Python functions.
unpredictable effects, including infinite recursion.
If *event* is ``PyFunction_EVENT_CREATE``, then the callback is invoked
- after `func` has been fully initialized. Otherwise, the callback is invoked
+ after *func* has been fully initialized. Otherwise, the callback is invoked
before the modification to *func* takes place, so the prior state of *func*
can be inspected. The runtime is permitted to optimize away the creation of
function objects when possible. In such cases no event will be emitted.
diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst
index 621da3eb069949c..afec8cbea93bccd 100644
--- a/Doc/c-api/gcsupport.rst
+++ b/Doc/c-api/gcsupport.rst
@@ -175,14 +175,18 @@ 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*:
-.. c:function:: void Py_VISIT(PyObject *o)
+.. c:macro:: Py_VISIT(o)
- If *o* is not ``NULL``, call the *visit* callback, with arguments *o*
+ If the :c:expr:`PyObject *` *o* is not ``NULL``, call the *visit* callback, with arguments *o*
and *arg*. If *visit* returns a non-zero value, then return it.
Using this macro, :c:member:`~PyTypeObject.tp_traverse` handlers
look like::
@@ -277,7 +281,7 @@ the garbage collector.
Type of the visitor function to be passed to :c:func:`PyUnstable_GC_VisitObjects`.
*arg* is the same as the *arg* passed to ``PyUnstable_GC_VisitObjects``.
- Return ``0`` to continue iteration, return ``1`` to stop iteration. Other return
+ Return ``1`` to continue iteration, return ``0`` to stop iteration. Other return
values are reserved for now so behavior on returning anything else is undefined.
.. versionadded:: 3.12
diff --git a/Doc/c-api/gen.rst b/Doc/c-api/gen.rst
index 0eb5922f6da75f2..ae7bf7c94aa5ea9 100644
--- a/Doc/c-api/gen.rst
+++ b/Doc/c-api/gen.rst
@@ -35,12 +35,51 @@ than explicitly calling :c:func:`PyGen_New` or :c:func:`PyGen_NewWithQualName`.
.. c:function:: PyObject* PyGen_New(PyFrameObject *frame)
Create and return a new generator object based on the *frame* object.
- A reference to *frame* is stolen by this function. The argument must not be
- ``NULL``.
+ A reference to *frame* is ":term:`stolen `" by this function (even
+ on error). The argument must not be ``NULL``.
.. c:function:: PyObject* PyGen_NewWithQualName(PyFrameObject *frame, PyObject *name, PyObject *qualname)
Create and return a new generator object based on the *frame* object,
with ``__name__`` and ``__qualname__`` set to *name* and *qualname*.
- A reference to *frame* is stolen by this function. The *frame* argument
+ A reference to *frame* is ":term:`stolen `" by this function (even
+ on error). 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 ":term:`stolen `" by this function (even on error) 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
diff --git a/Doc/c-api/hash.rst b/Doc/c-api/hash.rst
index ddf0b3e15dbdbe2..bfbd737c031340e 100644
--- a/Doc/c-api/hash.rst
+++ b/Doc/c-api/hash.rst
@@ -11,41 +11,103 @@ 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 `_ ``P = 2**n -1``, used for numeric hash scheme.
+ The `Mersenne prime `_ ``P = 2**n -1``,
+ used for numeric hash scheme.
+
+ This corresponds to the :data:`sys.hash_info.modulus` constant.
.. 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`.
- .. c::member:: Py_hash_t (*const hash)(const void *, Py_ssize_t)
+ .. c:member:: Py_hash_t (*const hash)(const void *, Py_ssize_t)
Hash function.
@@ -53,14 +115,20 @@ 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
diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst
index 1054b38cb92f7d0..56cf3ec3c129a4e 100644
--- a/Doc/c-api/import.rst
+++ b/Doc/c-api/import.rst
@@ -136,14 +136,14 @@ Importing Modules
such modules have no way to know that the module object is an unknown (and
probably damaged with respect to the module author's intents) state.
- The module's :attr:`__spec__` and :attr:`__loader__` will be set, if
- not set already, with the appropriate values. The spec's loader will
- be set to the module's ``__loader__`` (if set) and to an instance of
- :class:`~importlib.machinery.SourceFileLoader` otherwise.
+ The module's :attr:`~module.__spec__` and :attr:`~module.__loader__` will be
+ set, if not set already, with the appropriate values. The spec's loader
+ will be set to the module's :attr:`!__loader__` (if set) and to an instance
+ of :class:`~importlib.machinery.SourceFileLoader` otherwise.
- The module's :attr:`__file__` attribute will be set to the code object's
- :attr:`~codeobject.co_filename`. If applicable, :attr:`__cached__` will also
- be set.
+ The module's :attr:`~module.__file__` attribute will be set to the code
+ 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.
@@ -155,29 +155,29 @@ Importing Modules
:c:func:`PyImport_ExecCodeModuleWithPathnames`.
.. versionchanged:: 3.12
- The setting of :attr:`__cached__` and :attr:`__loader__` is
- deprecated. See :class:`~importlib.machinery.ModuleSpec` for
+ The setting of :attr:`~module.__cached__` and :attr:`~module.__loader__`
+ is deprecated. See :class:`~importlib.machinery.ModuleSpec` for
alternatives.
.. c:function:: PyObject* PyImport_ExecCodeModuleEx(const char *name, PyObject *co, const char *pathname)
- Like :c:func:`PyImport_ExecCodeModule`, but the :attr:`__file__` attribute of
- the module object is set to *pathname* if it is non-``NULL``.
+ Like :c:func:`PyImport_ExecCodeModule`, but the :attr:`~module.__file__`
+ attribute of the module object is set to *pathname* if it is non-``NULL``.
See also :c:func:`PyImport_ExecCodeModuleWithPathnames`.
.. c:function:: PyObject* PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname, PyObject *cpathname)
- Like :c:func:`PyImport_ExecCodeModuleEx`, but the :attr:`__cached__`
+ 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 :attr:`__cached__` is deprecated. See
+ Setting :attr:`~module.__cached__` is deprecated. See
:class:`~importlib.machinery.ModuleSpec` for alternatives.
@@ -190,7 +190,7 @@ Importing Modules
.. versionadded:: 3.2
.. versionchanged:: 3.3
- Uses :func:`!imp.source_from_cache()` in calculating the source path if
+ Uses :func:`!imp.source_from_cache` in calculating the source path if
only the bytecode path is provided.
.. versionchanged:: 3.12
No longer uses the removed :mod:`!imp` module.
@@ -325,3 +325,10 @@ Importing Modules
If Python is initialized multiple times, :c:func:`PyImport_AppendInittab` or
:c:func:`PyImport_ExtendInittab` must be called before each Python
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.
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index 9e118d4f36145f8..8e0c2ce6444da82 100644
--- a/Doc/c-api/init.rst
+++ b/Doc/c-api/init.rst
@@ -7,7 +7,8 @@
Initialization, Finalization, and Threads
*****************************************
-See also :ref:`Python Initialization Configuration `.
+See :ref:`Python Initialization Configuration ` for details
+on how to configure the interpreter prior to initialization.
.. _pre-init-safe:
@@ -21,6 +22,15 @@ a few functions and the :ref:`global configuration variables
The following functions can be safely called before Python is initialized:
+* Functions that initialize the interpreter:
+
+ * :c:func:`Py_Initialize`
+ * :c:func:`Py_InitializeEx`
+ * :c:func:`Py_InitializeFromConfig`
+ * :c:func:`Py_BytesMain`
+ * :c:func:`Py_Main`
+ * the runtime pre-initialization functions covered in :ref:`init-config`
+
* Configuration functions:
* :c:func:`PyImport_AppendInittab`
@@ -32,6 +42,7 @@ The following functions can be safely called before Python is initialized:
* :c:func:`Py_SetProgramName`
* :c:func:`Py_SetPythonHome`
* :c:func:`PySys_ResetWarnOptions`
+ * the configuration functions covered in :ref:`init-config`
* Informative functions:
@@ -43,10 +54,12 @@ The following functions can be safely called before Python is initialized:
* :c:func:`Py_GetCopyright`
* :c:func:`Py_GetPlatform`
* :c:func:`Py_GetVersion`
+ * :c:func:`Py_IsInitialized`
* Utilities:
* :c:func:`Py_DecodeLocale`
+ * the status reporting and utility functions covered in :ref:`init-config`
* Memory allocators:
@@ -55,13 +68,20 @@ The following functions can be safely called before Python is initialized:
* :c:func:`PyMem_RawCalloc`
* :c:func:`PyMem_RawFree`
+* Synchronization:
+
+ * :c:func:`PyMutex_Lock`
+ * :c:func:`PyMutex_Unlock`
+
.. note::
- The following functions **should not be called** before
- :c:func:`Py_Initialize`: :c:func:`Py_EncodeLocale`, :c:func:`Py_GetPath`,
+ Despite their apparent similarity to some of the functions listed above,
+ the following functions **should not be called** before the interpreter has
+ been initialized: :c:func:`Py_EncodeLocale`, :c:func:`Py_GetPath`,
:c:func:`Py_GetPrefix`, :c:func:`Py_GetExecPrefix`,
:c:func:`Py_GetProgramFullPath`, :c:func:`Py_GetPythonHome`,
- :c:func:`Py_GetProgramName` and :c:func:`PyEval_InitThreads`.
+ :c:func:`Py_GetProgramName`, :c:func:`PyEval_InitThreads`, and
+ :c:func:`Py_RunMain`.
.. _global-conf-vars:
@@ -183,7 +203,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2.
Set by the :option:`-i` option.
- .. deprecated:: 3.12
+ .. deprecated-removed:: 3.12 3.15
.. c:var:: int Py_IsolatedFlag
@@ -341,34 +361,42 @@ Initializing and finalizing the interpreter
this should be called before using any other Python/C API functions; see
:ref:`Before Python Initialization ` for the few exceptions.
- This initializes
- the table of loaded modules (``sys.modules``), and creates the fundamental
- modules :mod:`builtins`, :mod:`__main__` and :mod:`sys`. It also initializes
- the module search path (``sys.path``). It does not set ``sys.argv``; use
- the new :c:type:`PyConfig` API of the :ref:`Python Initialization
- Configuration ` for that. This is a no-op when called for a
- second time
- (without calling :c:func:`Py_FinalizeEx` first). There is no return value; it is a
- fatal error if the initialization fails.
-
- Use the :c:func:`Py_InitializeFromConfig` function to customize the
+ This initializes the table of loaded modules (``sys.modules``), and creates
+ the fundamental modules :mod:`builtins`, :mod:`__main__` and :mod:`sys`.
+ It also initializes the module search path (``sys.path``). It does not set
+ ``sys.argv``; use the :ref:`Python Initialization Configuration `
+ API for that. This is a no-op when called for a second time (without calling
+ :c:func:`Py_FinalizeEx` first). There is no return value; it is a fatal
+ error if the initialization fails.
+
+ Use :c:func:`Py_InitializeFromConfig` to customize the
:ref:`Python Initialization Configuration `.
.. note::
- On Windows, changes the console mode from ``O_TEXT`` to ``O_BINARY``, which will
- also affect non-Python uses of the console using the C Runtime.
+ On Windows, changes the console mode from ``O_TEXT`` to ``O_BINARY``,
+ which will also affect non-Python uses of the console using the C Runtime.
.. c:function:: void Py_InitializeEx(int initsigs)
This function works like :c:func:`Py_Initialize` if *initsigs* is ``1``. If
- *initsigs* is ``0``, it skips initialization registration of signal handlers, which
- might be useful when Python is embedded.
+ *initsigs* is ``0``, it skips initialization registration of signal handlers,
+ which may be useful when CPython is embedded as part of a larger application.
- Use the :c:func:`Py_InitializeFromConfig` function to customize the
+ Use :c:func:`Py_InitializeFromConfig` to customize the
:ref:`Python Initialization Configuration `.
+.. c:function:: PyStatus Py_InitializeFromConfig(const PyConfig *config)
+
+ Initialize Python from *config* configuration, as described in
+ :ref:`init-from-config`.
+
+ See the :ref:`init-config` section for details on pre-initializing the
+ interpreter, populating the runtime configuration structure, and querying
+ the returned status structure.
+
+
.. c:function:: int Py_IsInitialized()
Return true (nonzero) when the Python interpreter has been initialized, false
@@ -391,9 +419,16 @@ Initializing and finalizing the interpreter
:c:func:`Py_NewInterpreter` below) that were created and not yet destroyed since
the last call to :c:func:`Py_Initialize`. Ideally, this frees all memory
allocated by the Python interpreter. This is a no-op when called for a second
- time (without calling :c:func:`Py_Initialize` again first). Normally the
- return value is ``0``. If there were errors during finalization
- (flushing buffered data), ``-1`` is returned.
+ time (without calling :c:func:`Py_Initialize` again first).
+
+ Since this is the reverse of :c:func:`Py_Initialize`, it should be called
+ in the same thread with the same interpreter active. That means
+ the main thread and the main interpreter.
+ This should never be called while :c:func:`Py_RunMain` is running.
+
+ Normally the return value is ``0``.
+ If there were errors during finalization (flushing buffered data),
+ ``-1`` is returned.
This function is provided for a number of reasons. An embedding application
might want to restart Python without having to restart the application itself.
@@ -412,18 +447,116 @@ Initializing and finalizing the interpreter
freed. Some memory allocated by extension modules may not be freed. Some
extensions may not work properly if their initialization routine is called more
than once; this can happen if an application calls :c:func:`Py_Initialize` and
- :c:func:`Py_FinalizeEx` more than once.
+ :c:func:`Py_FinalizeEx` more than once. :c:func:`Py_FinalizeEx` must not be
+ called recursively from within itself. Therefore, it must not be called by
+ any code that may be run as part of the interpreter shutdown process, such
+ as :py:mod:`atexit` handlers, object finalizers, or any code that may be run
+ while flushing the stdout and stderr files.
.. audit-event:: cpython._PySys_ClearAuditHooks "" c.Py_FinalizeEx
.. versionadded:: 3.6
+
.. c:function:: void Py_Finalize()
This is a backwards-compatible version of :c:func:`Py_FinalizeEx` that
disregards the return value.
+.. c:function:: int Py_BytesMain(int argc, char **argv)
+
+ Similar to :c:func:`Py_Main` but *argv* is an array of bytes strings,
+ allowing the calling application to delegate the text decoding step to
+ the CPython runtime.
+
+ .. versionadded:: 3.8
+
+
+.. c:function:: int Py_Main(int argc, wchar_t **argv)
+
+ The main program for the standard interpreter, encapsulating a full
+ initialization/finalization cycle, as well as additional
+ behaviour to implement reading configurations settings from the environment
+ and command line, and then executing ``__main__`` in accordance with
+ :ref:`using-on-cmdline`.
+
+ This is made available for programs which wish to support the full CPython
+ command line interface, rather than just embedding a Python runtime in a
+ larger application.
+
+ The *argc* and *argv* parameters are similar to those which are passed to a
+ C program's :c:func:`main` function, except that the *argv* entries are first
+ converted to ``wchar_t`` using :c:func:`Py_DecodeLocale`. It is also
+ important to note that the argument list entries may be modified to point to
+ strings other than those passed in (however, the contents of the strings
+ pointed to by the argument list are not modified).
+
+ The return value is ``2`` if the argument list does not represent a valid
+ Python command line, and otherwise the same as :c:func:`Py_RunMain`.
+
+ In terms of the CPython runtime configuration APIs documented in the
+ :ref:`runtime configuration ` section (and without accounting
+ for error handling), ``Py_Main`` is approximately equivalent to::
+
+ PyConfig config;
+ PyConfig_InitPythonConfig(&config);
+ PyConfig_SetArgv(&config, argc, argv);
+ Py_InitializeFromConfig(&config);
+ PyConfig_Clear(&config);
+
+ Py_RunMain();
+
+ In normal usage, an embedding application will call this function
+ *instead* of calling :c:func:`Py_Initialize`, :c:func:`Py_InitializeEx` or
+ :c:func:`Py_InitializeFromConfig` directly, and all settings will be applied
+ as described elsewhere in this documentation. If this function is instead
+ called *after* a preceding runtime initialization API call, then exactly
+ which environmental and command line configuration settings will be updated
+ is version dependent (as it depends on which settings correctly support
+ being modified after they have already been set once when the runtime was
+ first initialized).
+
+
+.. c:function:: int Py_RunMain(void)
+
+ Executes the main module in a fully configured CPython runtime.
+
+ Executes the command (:c:member:`PyConfig.run_command`), the script
+ (:c:member:`PyConfig.run_filename`) or the module
+ (:c:member:`PyConfig.run_module`) specified on the command line or in the
+ configuration. If none of these values are set, runs the interactive Python
+ prompt (REPL) using the ``__main__`` module's global namespace.
+
+ If :c:member:`PyConfig.inspect` is not set (the default), the return value
+ will be ``0`` if the interpreter exits normally (that is, without raising
+ an exception), the exit status of an unhandled :exc:`SystemExit`, or ``1``
+ for any other unhandled exception.
+
+ If :c:member:`PyConfig.inspect` is set (such as when the :option:`-i` option
+ is used), rather than returning when the interpreter exits, execution will
+ instead resume in an interactive Python prompt (REPL) using the ``__main__``
+ module's global namespace. If the interpreter exited with an exception, it
+ is immediately raised in the REPL session. The function return value is
+ then determined by the way the *REPL session* terminates: ``0``, ``1``, or
+ the status of a :exc:`SystemExit`, as specified above.
+
+ This function always finalizes the Python interpreter before it returns.
+
+ See :ref:`Python Configuration ` for an example of a
+ customized Python that always runs in isolated mode using
+ :c:func:`Py_RunMain`.
+
+.. c:function:: int PyUnstable_AtExit(PyInterpreterState *interp, void (*func)(void *), void *data)
+
+ Register an :mod:`atexit` callback for the target interpreter *interp*.
+ This is similar to :c:func:`Py_AtExit`, but takes an explicit interpreter and
+ data pointer for the callback.
+
+ The :term:`GIL` must be held for *interp*.
+
+ .. versionadded:: 3.13
+
Process-wide parameters
=======================
@@ -451,7 +584,7 @@ Process-wide parameters
interpreter will change the contents of this storage.
Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a
- :c:expr:`wchar_*` string.
+ :c:expr:`wchar_t*` string.
.. deprecated:: 3.11
@@ -481,7 +614,7 @@ Process-wide parameters
returned string points into static storage; the caller should not modify its
value. This corresponds to the :makevar:`prefix` variable in the top-level
:file:`Makefile` and the :option:`--prefix` argument to the :program:`configure`
- script at build time. The value is available to Python code as ``sys.prefix``.
+ script at build time. The value is available to Python code as ``sys.base_prefix``.
It is only useful on Unix. See also the next function.
This function should not be called before :c:func:`Py_Initialize`, otherwise
@@ -491,7 +624,8 @@ Process-wide parameters
It now returns ``NULL`` if called before :c:func:`Py_Initialize`.
.. deprecated-removed:: 3.13 3.15
- Get :data:`sys.prefix` instead.
+ Get :data:`sys.base_prefix` instead, or :data:`sys.prefix` if
+ :ref:`virtual environments ` need to be handled.
.. c:function:: wchar_t* Py_GetExecPrefix()
@@ -504,7 +638,8 @@ Process-wide parameters
should not modify its value. This corresponds to the :makevar:`exec_prefix`
variable in the top-level :file:`Makefile` and the ``--exec-prefix``
argument to the :program:`configure` script at build time. The value is
- available to Python code as ``sys.exec_prefix``. It is only useful on Unix.
+ available to Python code as ``sys.base_exec_prefix``. It is only useful on
+ Unix.
Background: The exec-prefix differs from the prefix when platform dependent
files (such as executables and shared libraries) are installed in a different
@@ -535,7 +670,8 @@ Process-wide parameters
It now returns ``NULL`` if called before :c:func:`Py_Initialize`.
.. deprecated-removed:: 3.13 3.15
- Get :data:`sys.exec_prefix` instead.
+ Get :data:`sys.base_exec_prefix` instead, or :data:`sys.exec_prefix` if
+ :ref:`virtual environments ` need to be handled.
.. c:function:: wchar_t* Py_GetProgramFullPath()
@@ -690,7 +826,7 @@ Process-wide parameters
directory (``"."``).
Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a
- :c:expr:`wchar_*` string.
+ :c:expr:`wchar_t*` string.
See also :c:member:`PyConfig.orig_argv` and :c:member:`PyConfig.argv`
members of the :ref:`Python Initialization Configuration `.
@@ -726,7 +862,7 @@ Process-wide parameters
:option:`-I`.
Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a
- :c:expr:`wchar_*` string.
+ :c:expr:`wchar_t*` string.
See also :c:member:`PyConfig.orig_argv` and :c:member:`PyConfig.argv`
members of the :ref:`Python Initialization Configuration `.
@@ -752,7 +888,7 @@ Process-wide parameters
this storage.
Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a
- :c:expr:`wchar_*` string.
+ :c:expr:`wchar_t*` string.
.. deprecated:: 3.11
@@ -942,6 +1078,37 @@ thread, where the CPython global runtime was originally initialized.
The only exception is if :c:func:`exec` will be called immediately
after.
+.. _cautions-regarding-runtime-finalization:
+
+Cautions regarding runtime finalization
+---------------------------------------
+
+In the late stage of :term:`interpreter shutdown`, after attempting to wait for
+non-daemon threads to exit (though this can be interrupted by
+:class:`KeyboardInterrupt`) and running the :mod:`atexit` functions, the runtime
+is marked as *finalizing*: :c:func:`Py_IsFinalizing` and
+:func:`sys.is_finalizing` return true. At this point, only the *finalization
+thread* that initiated finalization (typically the main thread) is allowed to
+acquire the :term:`GIL`.
+
+If any thread, other than the finalization thread, attempts to acquire the GIL
+during finalization, either explicitly via :c:func:`PyGILState_Ensure`,
+:c:macro:`Py_END_ALLOW_THREADS`, :c:func:`PyEval_AcquireThread`, or
+:c:func:`!PyEval_AcquireLock`, or implicitly when the interpreter attempts to
+reacquire it after having yielded it, the thread enters **a permanently blocked
+state** where it remains until the program exits. In most cases this is
+harmless, but this can result in deadlock if a later stage of finalization
+attempts to acquire a lock owned by the blocked thread, or otherwise waits on
+the blocked thread.
+
+Gross? Yes. This prevents random crashes and/or unexpectedly skipped C++
+finalizations further up the call stack when such threads were forcibly exited
+here in CPython 3.13.7 and earlier. The CPython runtime GIL acquiring C APIs
+have never had any error reporting or handling expectations at GIL acquisition
+time that would've allowed for graceful exit from this situation. Changing that
+would require new stable C APIs and rewriting the majority of C code in the
+CPython ecosystem to use those with error handling.
+
High-level API
--------------
@@ -961,6 +1128,12 @@ code, or when embedding the Python interpreter:
interpreter lock is also shared by all threads, regardless of to which
interpreter they belong.
+ .. versionchanged:: 3.12
+
+ :pep:`684` introduced the possibility
+ of a :ref:`per-interpreter GIL `.
+ See :c:func:`Py_NewInterpreterFromConfig`.
+
.. c:type:: PyThreadState
@@ -1015,11 +1188,14 @@ code, or when embedding the Python interpreter:
ensues.
.. note::
- Calling this function from a thread when the runtime is finalizing
- will terminate the thread, even if the thread was not created by Python.
- You can use :c:func:`Py_IsFinalizing` or :func:`sys.is_finalizing` to
- check if the interpreter is in process of being finalized before calling
- this function to avoid unwanted termination.
+ Calling this function from a thread when the runtime is finalizing will
+ hang the thread until the program exits, even if the thread was not
+ created by Python. Refer to
+ :ref:`cautions-regarding-runtime-finalization` for more details.
+
+ .. versionchanged:: 3.13.8
+ Hangs the current thread, rather than terminating it, if called while the
+ interpreter is finalizing.
.. c:function:: PyThreadState* PyThreadState_Get()
@@ -1044,13 +1220,27 @@ code, or when embedding the Python interpreter:
.. c:function:: PyThreadState* PyThreadState_Swap(PyThreadState *tstate)
Swap the current thread state with the thread state given by the argument
- *tstate*, which may be ``NULL``. The global interpreter lock must be held
- and is not released.
+ *tstate*, which may be ``NULL``.
+ The :term:`GIL` does not need to be held, but will be held upon returning
+ if *tstate* is non-``NULL``.
The following functions use thread-local storage, and are not compatible
with sub-interpreters:
+.. c:type:: PyGILState_STATE
+
+ The type of the value returned by :c:func:`PyGILState_Ensure` and passed to
+ :c:func:`PyGILState_Release`.
+
+ .. c:enumerator:: PyGILState_LOCKED
+
+ The GIL was already held when :c:func:`PyGILState_Ensure` was called.
+
+ .. c:enumerator:: PyGILState_UNLOCKED
+
+ The GIL was not held when :c:func:`PyGILState_Ensure` was called.
+
.. c:function:: PyGILState_STATE PyGILState_Ensure()
Ensure that the current thread is ready to call the Python C API regardless
@@ -1074,11 +1264,14 @@ with sub-interpreters:
to call arbitrary Python code. Failure is a fatal error.
.. note::
- Calling this function from a thread when the runtime is finalizing
- will terminate the thread, even if the thread was not created by Python.
- You can use :c:func:`Py_IsFinalizing` or :func:`sys.is_finalizing` to
- check if the interpreter is in process of being finalized before calling
- this function to avoid unwanted termination.
+ Calling this function from a thread when the runtime is finalizing will
+ hang the thread until the program exits, even if the thread was not
+ created by Python. Refer to
+ :ref:`cautions-regarding-runtime-finalization` for more details.
+
+ .. versionchanged:: 3.13.8
+ Hangs the current thread, rather than terminating it, if called while the
+ interpreter is finalizing.
.. c:function:: void PyGILState_Release(PyGILState_STATE)
@@ -1192,9 +1385,12 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
must be held.
.. versionchanged:: 3.9
- This function now calls the :c:member:`PyThreadState.on_delete` callback.
+ This function now calls the :c:member:`!PyThreadState.on_delete` callback.
Previously, that happened in :c:func:`PyThreadState_Delete`.
+ .. versionchanged:: 3.13
+ The :c:member:`!PyThreadState.on_delete` callback was removed.
+
.. c:function:: void PyThreadState_Delete(PyThreadState *tstate)
@@ -1206,7 +1402,7 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
.. c:function:: void PyThreadState_DeleteCurrent(void)
Destroy the current thread state and release the global interpreter lock.
- Like :c:func:`PyThreadState_Delete`, the global interpreter lock need not
+ Like :c:func:`PyThreadState_Delete`, the global interpreter lock must
be held. The thread state must have been reset with a previous call
to :c:func:`PyThreadState_Clear`.
@@ -1267,7 +1463,7 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
Get the current interpreter.
- Issue a fatal error if there no current Python thread state or no current
+ Issue a fatal error if there is no current Python thread state or no current
interpreter. It cannot return NULL.
The caller must hold the GIL.
@@ -1294,8 +1490,22 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
This is not a replacement for :c:func:`PyModule_GetState()`, which
extensions should use to store interpreter-specific state information.
+ The returned dictionary is borrowed from the interpreter and is valid until
+ interpreter shutdown.
+
.. versionadded:: 3.8
+
+.. c:function:: PyObject* PyUnstable_InterpreterState_GetMainModule(PyInterpreterState *interp)
+
+ Return a :term:`strong reference` to the ``__main__`` :ref:`module object `
+ for the given interpreter.
+
+ The caller must hold the GIL.
+
+ .. versionadded:: 3.13
+
+
.. c:type:: PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag)
Type of a frame evaluation function.
@@ -1356,17 +1566,20 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
If this thread already has the lock, deadlock ensues.
.. note::
- Calling this function from a thread when the runtime is finalizing
- will terminate the thread, even if the thread was not created by Python.
- You can use :c:func:`Py_IsFinalizing` or :func:`sys.is_finalizing` to
- check if the interpreter is in process of being finalized before calling
- this function to avoid unwanted termination.
+ Calling this function from a thread when the runtime is finalizing will
+ hang the thread until the program exits, even if the thread was not
+ created by Python. Refer to
+ :ref:`cautions-regarding-runtime-finalization` for more details.
.. versionchanged:: 3.8
Updated to be consistent with :c:func:`PyEval_RestoreThread`,
:c:func:`Py_END_ALLOW_THREADS`, and :c:func:`PyGILState_Ensure`,
and terminate the current thread if called while the interpreter is finalizing.
+ .. versionchanged:: 3.13.8
+ Hangs the current thread, rather than terminating it, if called while the
+ interpreter is finalizing.
+
:c:func:`PyEval_RestoreThread` is a higher-level function which is always
available (even when threads have not been initialized).
@@ -1548,7 +1761,11 @@ function. You can create and destroy them using the following functions:
.check_multi_interp_extensions = 1,
.gil = PyInterpreterConfig_OWN_GIL,
};
- PyThreadState *tstate = Py_NewInterpreterFromConfig(&config);
+ PyThreadState *tstate = NULL;
+ PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config);
+ if (PyStatus_Exception(status)) {
+ Py_ExitStatusException(status);
+ }
Note that the config is used only briefly and does not get modified.
During initialization the config's values are converted into various
@@ -1622,6 +1839,8 @@ function. You can create and destroy them using the following functions:
haven't been explicitly destroyed at that point.
+.. _per-interpreter-gil:
+
A Per-Interpreter GIL
---------------------
@@ -1633,7 +1852,7 @@ being blocked by other interpreters or blocking any others. Thus a
single Python process can truly take advantage of multiple CPU cores
when running Python code. The isolation also encourages a different
approach to concurrency than that of just using threads.
-(See :pep:`554`.)
+(See :pep:`554` and :pep:`684`.)
Using an isolated interpreter requires vigilance in preserving that
isolation. That especially means not sharing any objects or mutable
@@ -1741,6 +1960,29 @@ pointer and a void pointer argument.
called from the main interpreter. Each subinterpreter now has its own
list of scheduled calls.
+ .. versionchanged:: 3.12
+ This function now always schedules *func* to be run in the main
+ interpreter.
+
+
+.. c:function:: int Py_MakePendingCalls(void)
+
+ Execute all pending calls. This is usually executed automatically by the
+ interpreter.
+
+ This function returns ``0`` on success, and returns ``-1`` with an exception
+ set on failure.
+
+ If this is not called in the main thread of the main
+ interpreter, this function does nothing and returns ``0``.
+ The caller must hold the :term:`GIL`.
+
+ .. versionadded:: 3.1
+
+ .. versionchanged:: 3.12
+ This function only runs pending calls in the main interpreter.
+
+
.. _profiling:
Profiling and Tracing
@@ -1809,7 +2051,7 @@ Python-level trace functions in previous versions.
*what* when after any bytecode is processed after which the exception becomes
set within the frame being executed. The effect of this is that as exception
propagation causes the Python stack to unwind, the callback is called upon
- return to each frame as the exception propagates. Only trace functions receives
+ return to each frame as the exception propagates. Only trace functions receive
these events; they are not needed by the profiler.
@@ -1937,7 +2179,7 @@ Reference tracing
the tracer function is called. Return ``0`` on success. Set an exception and
return ``-1`` on error.
- Not that tracer functions **must not** create Python objects inside or
+ Note that tracer functions **must not** create Python objects inside or
otherwise the call will be re-entrant. The tracer also **must not** clear
any existing exception or set an exception. The GIL will be held every time
the tracer function is called.
@@ -2152,3 +2394,368 @@ be used in new code.
.. c:function:: void PyThread_delete_key_value(int key)
.. c:function:: void PyThread_ReInitTLS()
+Synchronization Primitives
+==========================
+
+The C-API provides a basic mutual exclusion lock.
+
+.. c:type:: PyMutex
+
+ A mutual exclusion lock. The :c:type:`!PyMutex` should be initialized to
+ zero to represent the unlocked state. For example::
+
+ PyMutex mutex = {0};
+
+ Instances of :c:type:`!PyMutex` should not be copied or moved. Both the
+ contents and address of a :c:type:`!PyMutex` are meaningful, and it must
+ remain at a fixed, writable location in memory.
+
+ .. note::
+
+ A :c:type:`!PyMutex` currently occupies one byte, but the size should be
+ considered unstable. The size may change in future Python releases
+ without a deprecation period.
+
+ .. versionadded:: 3.13
+
+.. c:function:: void PyMutex_Lock(PyMutex *m)
+
+ Lock mutex *m*. If another thread has already locked it, the calling
+ thread will block until the mutex is unlocked. While blocked, the thread
+ will temporarily release the :term:`GIL` if it is held.
+
+ .. versionadded:: 3.13
+
+.. c:function:: void PyMutex_Unlock(PyMutex *m)
+
+ Unlock mutex *m*. The mutex must be locked --- otherwise, the function will
+ issue a fatal error.
+
+ .. versionadded:: 3.13
+
+.. _python-critical-section-api:
+
+Python Critical Section API
+---------------------------
+
+The critical section API provides a deadlock avoidance layer on top of
+per-object locks for :term:`free-threaded ` CPython. They are
+intended to replace reliance on the :term:`global interpreter lock`, and are
+no-ops in versions of Python with the global interpreter lock.
+
+Critical sections are intended to be used for custom types implemented
+in C-API extensions. They should generally not be used with built-in types like
+:class:`list` and :class:`dict` because their public C-APIs
+already use critical sections internally, with the notable
+exception of :c:func:`PyDict_Next`, which requires critical section
+to be acquired externally.
+
+Critical sections avoid deadlocks by implicitly suspending active critical
+sections, hence, they do not provide exclusive access such as provided by
+traditional locks like :c:type:`PyMutex`. When a critical section is started,
+the per-object lock for the object is acquired. If the code executed inside the
+critical section calls C-API functions then it can suspend the critical section thereby
+releasing the per-object lock, so other threads can acquire the per-object lock
+for the same object.
+
+The functions and structs used by the macros are exposed for cases
+where C macros are not available. They should only be used as in the
+given macro expansions. Note that the sizes and contents of the structures may
+change in future Python versions.
+
+.. note::
+
+ Operations that need to lock two objects at once must use
+ :c:macro:`Py_BEGIN_CRITICAL_SECTION2`. You *cannot* use nested critical
+ sections to lock more than one object at once, because the inner critical
+ section may suspend the outer critical sections. This API does not provide
+ a way to lock more than two objects at once.
+
+Example usage::
+
+ static PyObject *
+ set_field(MyObject *self, PyObject *value)
+ {
+ Py_BEGIN_CRITICAL_SECTION(self);
+ Py_SETREF(self->field, Py_XNewRef(value));
+ Py_END_CRITICAL_SECTION();
+ Py_RETURN_NONE;
+ }
+
+In the above example, :c:macro:`Py_SETREF` calls :c:macro:`Py_DECREF`, which
+can call arbitrary code through an object's deallocation function. The critical
+section API avoids potential deadlocks due to reentrancy and lock ordering
+by allowing the runtime to temporarily suspend the critical section if the
+code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`.
+
+.. c:macro:: Py_BEGIN_CRITICAL_SECTION(op)
+
+ Acquires the per-object lock for the object *op* and begins a
+ critical section.
+
+ In the free-threaded build, this macro expands to::
+
+ {
+ PyCriticalSection _py_cs;
+ PyCriticalSection_Begin(&_py_cs, (PyObject*)(op))
+
+ In the default build, this macro expands to ``{``.
+
+ .. versionadded:: 3.13
+
+.. c:macro:: Py_END_CRITICAL_SECTION()
+
+ Ends the critical section and releases the per-object lock.
+
+ In the free-threaded build, this macro expands to::
+
+ PyCriticalSection_End(&_py_cs);
+ }
+
+ In the default build, this macro expands to ``}``.
+
+ .. versionadded:: 3.13
+
+.. c:macro:: Py_BEGIN_CRITICAL_SECTION2(a, b)
+
+ Acquires the per-objects locks for the objects *a* and *b* and begins a
+ critical section. The locks are acquired in a consistent order (lowest
+ address first) to avoid lock ordering deadlocks.
+
+ In the free-threaded build, this macro expands to::
+
+ {
+ PyCriticalSection2 _py_cs2;
+ PyCriticalSection2_Begin(&_py_cs2, (PyObject*)(a), (PyObject*)(b))
+
+ In the default build, this macro expands to ``{``.
+
+ .. versionadded:: 3.13
+
+.. c:macro:: Py_END_CRITICAL_SECTION2()
+
+ Ends the critical section and releases the per-object locks.
+
+ In the free-threaded build, this macro expands to::
+
+ PyCriticalSection2_End(&_py_cs2);
+ }
+
+ In the default build, this macro expands to ``}``.
+
+ .. versionadded:: 3.13
+
+
+Legacy Locking APIs
+-------------------
+
+These APIs are obsolete since Python 3.13 with the introduction of
+:c:type:`PyMutex`.
+
+.. versionchanged:: 3.15
+ These APIs are now a simple wrapper around ``PyMutex``.
+
+
+.. c:type:: PyThread_type_lock
+
+ A pointer to a mutual exclusion lock.
+
+
+.. c:type:: PyLockStatus
+
+ The result of acquiring a lock with a timeout.
+
+ .. c:namespace:: NULL
+
+ .. c:enumerator:: PY_LOCK_FAILURE
+
+ Failed to acquire the lock.
+
+ .. c:enumerator:: PY_LOCK_ACQUIRED
+
+ The lock was successfully acquired.
+
+ .. c:enumerator:: PY_LOCK_INTR
+
+ The lock was interrupted by a signal.
+
+
+.. c:function:: PyThread_type_lock PyThread_allocate_lock(void)
+
+ Allocate a new lock.
+
+ On success, this function returns a lock; on failure, this
+ function returns ``0`` without an exception set.
+
+ The caller does not need to hold the :term:`GIL`.
+
+ .. 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 the :term:`GIL`.
+
+
+.. 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 the :term:`GIL`.
+
+
+.. 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 the :term:`GIL`.
+
+
+.. 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 the :term:`GIL`.
+
+
+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 the :term:`GIL`.
+
+
+.. 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 the
+ :term:`GIL`.
+
+ .. 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 ` 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 the :term:`GIL`.
+
+
+.. 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 the
+ :term:`GIL`.
+
+ .. 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.
+
+
+.. 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 the :term:`GIL`.
+
+
+.. 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 the :term:`GIL`.
diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst
index 5195f6cccfe9dfd..7053b53537c5552 100644
--- a/Doc/c-api/init_config.rst
+++ b/Doc/c-api/init_config.rst
@@ -321,7 +321,7 @@ PyPreConfig
* Set :c:member:`PyConfig.filesystem_encoding` to ``"mbcs"``,
* Set :c:member:`PyConfig.filesystem_errors` to ``"replace"``.
- Initialized the from :envvar:`PYTHONLEGACYWINDOWSFSENCODING` environment
+ Initialized from the :envvar:`PYTHONLEGACYWINDOWSFSENCODING` environment
variable value.
Only available on Windows. ``#ifdef MS_WINDOWS`` macro can be used for
@@ -509,7 +509,7 @@ PyConfig
The :c:func:`PyConfig_Read` function only parses
:c:member:`PyConfig.argv` arguments once: :c:member:`PyConfig.parse_argv`
is set to ``2`` after arguments are parsed. Since Python arguments are
- strippped from :c:member:`PyConfig.argv`, parsing arguments twice would
+ stripped from :c:member:`PyConfig.argv`, parsing arguments twice would
parse the application options as Python options.
:ref:`Preinitialize Python ` if needed.
@@ -532,7 +532,7 @@ PyConfig
Most ``PyConfig`` methods :ref:`preinitialize Python ` if needed.
In that case, the Python preinitialization configuration
- (:c:type:`PyPreConfig`) in based on the :c:type:`PyConfig`. If configuration
+ (:c:type:`PyPreConfig`) is based on the :c:type:`PyConfig`. If configuration
fields which are in common with :c:type:`PyPreConfig` are tuned, they must
be set before calling a :c:type:`PyConfig` method:
@@ -610,9 +610,9 @@ PyConfig
.. c:member:: wchar_t* base_executable
- Python base executable: :data:`sys._base_executable`.
+ Python base executable: ``sys._base_executable``.
- Set by the :envvar:`__PYVENV_LAUNCHER__` environment variable.
+ Set by the ``__PYVENV_LAUNCHER__`` environment variable.
Set from :c:member:`PyConfig.executable` if ``NULL``.
@@ -1041,7 +1041,7 @@ PyConfig
The :c:func:`PyConfig_Read` function only parses
:c:member:`PyConfig.argv` arguments once: :c:member:`PyConfig.parse_argv`
is set to ``2`` after arguments are parsed. Since Python arguments are
- strippped from :c:member:`PyConfig.argv`, parsing arguments twice would
+ stripped from :c:member:`PyConfig.argv`, parsing arguments twice would
parse the application options as Python options.
Default: ``1`` in Python mode, ``0`` in isolated mode.
@@ -1093,7 +1093,7 @@ PyConfig
* On macOS, use :envvar:`PYTHONEXECUTABLE` environment variable if set.
* If the ``WITH_NEXT_FRAMEWORK`` macro is defined, use
- :envvar:`__PYVENV_LAUNCHER__` environment variable if set.
+ ``__PYVENV_LAUNCHER__`` environment variable if set.
* Use ``argv[0]`` of :c:member:`~PyConfig.argv` if available and
non-empty.
* Otherwise, use ``L"python"`` on Windows, or ``L"python3"`` on other
@@ -1304,8 +1304,7 @@ PyConfig
The :mod:`warnings` module adds :data:`sys.warnoptions` in the reverse
order: the last :c:member:`PyConfig.warnoptions` item becomes the first
- item of :data:`warnings.filters` which is checked first (highest
- priority).
+ item of ``warnings.filters`` which is checked first (highest priority).
The :option:`-W` command line options adds its value to
:c:member:`~PyConfig.warnoptions`, it can be used multiple times.
@@ -1348,14 +1347,13 @@ the :option:`-X` command line option.
The ``show_alloc_count`` field has been removed.
+.. _init-from-config:
+
Initialization with PyConfig
============================
-Function to initialize Python:
-
-.. c:function:: PyStatus Py_InitializeFromConfig(const PyConfig *config)
-
- Initialize Python from *config* configuration.
+Initializing the interpreter from a populated configuration struct is handled
+by calling :c:func:`Py_InitializeFromConfig`.
The caller is responsible to handle exceptions (error or exit) using
:c:func:`PyStatus_Exception` and :c:func:`Py_ExitStatusException`.
@@ -1585,26 +1583,6 @@ The ``__PYVENV_LAUNCHER__`` environment variable is used to set
:c:member:`PyConfig.base_executable`.
-Py_RunMain()
-============
-
-.. c:function:: int Py_RunMain(void)
-
- Execute the command (:c:member:`PyConfig.run_command`), the script
- (:c:member:`PyConfig.run_filename`) or the module
- (:c:member:`PyConfig.run_module`) specified on the command line or in the
- configuration.
-
- By default and when if :option:`-i` option is used, run the REPL.
-
- Finally, finalizes Python and returns an exit status that can be passed to
- the ``exit()`` function.
-
-See :ref:`Python Configuration ` for an example of
-customized Python always running in isolated mode using
-:c:func:`Py_RunMain`.
-
-
Py_GetArgcArgv()
================
@@ -1642,7 +1620,7 @@ initialization, the core feature of :pep:`432`:
Private provisional API:
-* :c:member:`PyConfig._init_main`: if set to ``0``,
+* ``PyConfig._init_main``: if set to ``0``,
:c:func:`Py_InitializeFromConfig` stops at the "Core" initialization phase.
.. c:function:: PyStatus _Py_InitializeMain(void)
diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst
index 8ef463e3f88ca8f..0259d809c6cbe73 100644
--- a/Doc/c-api/intro.rst
+++ b/Doc/c-api/intro.rst
@@ -117,7 +117,7 @@ complete listing.
item defined in the module file. Example::
static struct PyModuleDef spam_module = {
- PyModuleDef_HEAD_INIT,
+ .m_base = PyModuleDef_HEAD_INIT,
.m_name = "spam",
...
};
@@ -125,7 +125,7 @@ complete listing.
PyMODINIT_FUNC
PyInit_spam(void)
{
- return PyModule_Create(&spam_module);
+ return PyModuleDef_Init(&spam_module);
}
@@ -133,12 +133,45 @@ 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_ALIGNED(num)
+
+ Specify alignment to *num* bytes on compilers that support it.
+
+ Consider using the C11 standard ``_Alignas`` specifier over this macro.
+
+.. c:macro:: Py_ARITHMETIC_RIGHT_SHIFT(type, integer, positions)
+
+ Similar to ``integer >> positions``, but forces sign extension, as the C
+ standard does not define whether a right-shift of a signed integer will
+ perform sign extension or a zero-fill.
+
+ *integer* should be any signed integer type.
+ *positions* is the number of positions to shift to the right.
+
+ Both *integer* and *positions* can be evaluated more than once;
+ consequently, avoid directly passing a function call or some other
+ operation with side-effects to this macro. Instead, store the result as a
+ variable and then pass it.
+
+ *type* is unused and only kept for backwards compatibility. Historically,
+ *type* was used to cast *integer*.
+
+ .. versionchanged:: 3.1
+
+ This macro is now valid for all signed integer types, not just those for
+ which ``unsigned type`` is legal. As a result, *type* is no longer
+ used.
+
.. c:macro:: Py_ALWAYS_INLINE
Ask the compiler to always inline a static inline function. The compiler can
- ignore it and decides to not inline the function.
+ ignore it and decide to not inline the function.
It can be used to inline performance critical static inline functions when
building Python in debug mode with function inlining disabled. For example,
@@ -157,6 +190,15 @@ complete listing.
.. versionadded:: 3.11
+.. c:macro:: Py_CAN_START_THREADS
+
+ If this macro is defined, then the current system is able to start threads.
+
+ Currently, all systems supported by CPython (per :pep:`11`), with the
+ exception of some WebAssembly platforms, support starting threads.
+
+ .. versionadded:: 3.13
+
.. c:macro:: Py_CHARMASK(c)
Argument must be a character or an integer in the range [-128, 127] or [0,
@@ -174,11 +216,54 @@ complete listing.
.. versionchanged:: 3.8
MSVC support was added.
+.. c:macro:: Py_FORCE_EXPANSION(X)
+
+ This is equivalent to ``X``, which is useful for token-pasting in
+ macros, as macro expansions in *X* are forcefully evaluated by the
+ preprocessor.
+
+.. c:macro:: Py_GCC_ATTRIBUTE(name)
+
+ Use a GCC attribute *name*, hiding it from compilers that don't support GCC
+ attributes (such as MSVC).
+
+ This expands to ``__attribute__((name))`` on a GCC compiler, and expands
+ to nothing on compilers that don't support GCC attributes.
+
.. c:macro:: Py_GETENV(s)
Like ``getenv(s)``, but returns ``NULL`` if :option:`-E` was passed on the
command line (see :c:member:`PyConfig.use_environment`).
+.. c:macro:: Py_LL(number)
+
+ Use *number* as a ``long long`` integer literal.
+
+ This usally expands to *number* followed by ``LL``, but will expand to some
+ compiler-specific suffixes (such as ``I64``) on older compilers.
+
+ In modern versions of Python, this macro is not very useful, as C99 and
+ later require the ``LL`` suffix to be valid for an integer.
+
+.. c:macro:: Py_LOCAL(type)
+
+ Declare a function returning the specified *type* using a fast-calling
+ qualifier for functions that are local to the current file.
+ Semantically, this is equivalent to ``static type``.
+
+.. c:macro:: Py_LOCAL_INLINE(type)
+
+ Equivalent to :c:macro:`Py_LOCAL` but additionally requests the function
+ be inlined.
+
+.. c:macro:: Py_LOCAL_SYMBOL
+
+ Macro used to declare a symbol as local to the shared library (hidden).
+ On supported platforms, it ensures the symbol is not exported.
+
+ On compatible versions of GCC/Clang, it
+ expands to ``__attribute__((visibility("hidden")))``.
+
.. c:macro:: Py_MAX(x, y)
Return the maximum value between ``x`` and ``y``.
@@ -209,6 +294,22 @@ complete listing.
.. versionadded:: 3.11
+.. c:macro:: Py_SAFE_DOWNCAST(value, larger, smaller)
+
+ Cast *value* to type *smaller* from type *larger*, validating that no
+ information was lost.
+
+ On release builds of Python, this is roughly equivalent to
+ ``(smaller) value`` (in C++, ``static_cast(value)`` will be
+ used instead).
+
+ On debug builds (implying that :c:macro:`Py_DEBUG` is defined), this asserts
+ that no information was lost with the cast from *larger* to *smaller*.
+
+ *value*, *larger*, and *smaller* may all be evaluated more than once in the
+ expression; consequently, do not pass an expression with side-effects directly to
+ this macro.
+
.. c:macro:: Py_STRINGIFY(x)
Convert ``x`` to a C string. E.g. ``Py_STRINGIFY(123)`` returns
@@ -216,6 +317,14 @@ complete listing.
.. versionadded:: 3.4
+.. c:macro:: Py_ULL(number)
+
+ Similar to :c:macro:`Py_LL`, but *number* will be an ``unsigned long long``
+ literal instead. This is done by appending ``U`` to the result of ``Py_LL``.
+
+ In modern versions of Python, this macro is not very useful, as C99 and
+ later require the ``ULL``/``LLU`` suffixes to be valid for an integer.
+
.. c:macro:: Py_UNREACHABLE()
Use this when you have a code path that cannot be reached by design.
@@ -227,8 +336,8 @@ complete listing.
avoids a warning about unreachable code. For example, the macro is
implemented with ``__builtin_unreachable()`` on GCC in release mode.
- A use for ``Py_UNREACHABLE()`` is following a call a function that
- never returns but that is not declared :c:macro:`_Py_NO_RETURN`.
+ A use for ``Py_UNREACHABLE()`` is following a call to a function that
+ never returns but that is not declared ``_Py_NO_RETURN``.
If a code path is very unlikely code but can be reached under exceptional
case, this macro must not be used. For example, under low memory condition
@@ -245,9 +354,32 @@ 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
@@ -279,6 +411,70 @@ 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])
+
+
+.. c:macro:: Py_EXPORTED_SYMBOL
+
+ Macro used to declare a symbol (function or data) as exported.
+ On Windows, this expands to ``__declspec(dllexport)``.
+ On compatible versions of GCC/Clang, it
+ expands to ``__attribute__((visibility("default")))``.
+ This macro is for defining the C API itself; extension modules should not use it.
+
+
+.. c:macro:: Py_IMPORTED_SYMBOL
+
+ Macro used to declare a symbol as imported.
+ On Windows, this expands to ``__declspec(dllimport)``.
+ This macro is for defining the C API itself; extension modules should not use it.
+
+
+.. c:macro:: PyAPI_FUNC(type)
+
+ Macro used by CPython to declare a function as part of the C API.
+ Its expansion depends on the platform and build configuration.
+ This macro is intended for defining CPython's C API itself;
+ extension modules should not use it for their own symbols.
+
+
+.. c:macro:: PyAPI_DATA(type)
+
+ Macro used by CPython to declare a public global variable as part of the C API.
+ Its expansion depends on the platform and build configuration.
+ This macro is intended for defining CPython's C API itself;
+ extension modules should not use it for their own symbols.
+
+.. c:macro:: Py_VA_COPY
+
+ This is a :term:`soft deprecated` alias to the C99-standard ``va_copy``
+ function.
+
+ Historically, this would use a compiler-specific method to copy a ``va_list``.
+
+ .. versionchanged:: 3.6
+ This is now an alias to ``va_copy``.
+
.. _api-objects:
@@ -396,9 +592,12 @@ the caller is said to *borrow* the reference. Nothing needs to be done for a
Conversely, when a calling function passes in a reference to an object, there
are two possibilities: the function *steals* a reference to the object, or it
-does not. *Stealing a reference* means that when you pass a reference to a
-function, that function assumes that it now owns that reference, and you are not
-responsible for it any longer.
+does not.
+
+*Stealing a reference* means that when you pass a reference to a
+function, that function assumes that it now owns that reference.
+Since the new owner can use :c:func:`!Py_DECREF` at its discretion,
+you (the caller) must not use that reference after the call.
.. index::
single: PyList_SetItem (C function)
@@ -825,7 +1024,7 @@ in the Unix build, compiler optimization is disabled.
In addition to the reference count debugging described below, extra checks are
performed, see :ref:`Python Debug Build `.
-Defining :c:macro:`Py_TRACE_REFS` enables reference tracing
+Defining ``Py_TRACE_REFS`` enables reference tracing
(see the :option:`configure --with-trace-refs option <--with-trace-refs>`).
When defined, a circular doubly linked list of active objects is maintained by adding two extra
fields to every :c:type:`PyObject`. Total allocations are tracked as well. Upon
@@ -834,3 +1033,41 @@ after every statement run by the interpreter.)
Please refer to :file:`Misc/SpecialBuilds.txt` in the Python source distribution
for more detailed information.
+
+
+.. _c-api-tools:
+
+Recommended third party tools
+=============================
+
+The following third party tools offer both simpler and more sophisticated
+approaches to creating C, C++ and Rust extensions for Python:
+
+* `Cython `_
+* `cffi `_
+* `HPy `_
+* `nanobind `_ (C++)
+* `Numba `_
+* `pybind11 `_ (C++)
+* `PyO3 `_ (Rust)
+* `SWIG `_
+
+Using tools such as these can help avoid writing code that is tightly bound to
+a particular version of CPython, avoid reference counting errors, and focus
+more on your own code than on using the CPython API. In general, new versions
+of Python can be supported by updating the tool, and your code will often use
+newer and more efficient APIs automatically. Some tools also support compiling
+for other implementations of Python from a single set of sources.
+
+These projects are not supported by the same people who maintain Python, and
+issues need to be raised with the projects directly. Remember to check that the
+project is still maintained and supported, as the list above may become
+outdated.
+
+.. seealso::
+
+ `Python Packaging User Guide: Binary Extensions `_
+ The Python Packaging User Guide not only covers several available
+ tools that simplify the creation of binary extensions, but also
+ discusses the various reasons why creating an extension module may be
+ desirable in the first place.
diff --git a/Doc/c-api/iterator.rst b/Doc/c-api/iterator.rst
index 6b7ba8c99791634..bfbfe3c92799809 100644
--- a/Doc/c-api/iterator.rst
+++ b/Doc/c-api/iterator.rst
@@ -50,3 +50,72 @@ 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.
diff --git a/Doc/c-api/list.rst b/Doc/c-api/list.rst
index 53eb54d3e1021a3..1d1c6e8658de385 100644
--- a/Doc/c-api/list.rst
+++ b/Doc/c-api/list.rst
@@ -38,9 +38,12 @@ List Objects
.. note::
If *len* is greater than zero, the returned list object's items are
- set to ``NULL``. Thus you cannot use abstract API functions such as
- :c:func:`PySequence_SetItem` or expose the object to Python code before
- setting all items to a real object with :c:func:`PyList_SetItem`.
+ set to ``NULL``. Thus you cannot use abstract API functions such as
+ :c:func:`PySequence_SetItem` or expose the object to Python code before
+ setting all items to a real object with :c:func:`PyList_SetItem` or
+ :c:func:`PyList_SET_ITEM()`. The following APIs are safe APIs before
+ the list is fully initialized: :c:func:`PyList_SetItem()` and :c:func:`PyList_SET_ITEM()`.
+
.. c:function:: Py_ssize_t PyList_Size(PyObject *list)
@@ -85,8 +88,10 @@ List Objects
.. note::
- This function "steals" a reference to *item* and discards a reference to
- an item already in the list at the affected position.
+ This function ":term:`steals `" a reference to *item*,
+ even on error.
+ On success, it discards a reference to an item already in the list
+ at the affected position (unless it was ``NULL``).
.. c:function:: void PyList_SET_ITEM(PyObject *list, Py_ssize_t i, PyObject *o)
@@ -100,7 +105,7 @@ List Objects
.. note::
- This macro "steals" a reference to *item*, and, unlike
+ This macro ":term:`steals `" a reference to *item*, and, unlike
:c:func:`PyList_SetItem`, does *not* discard a reference to any item that
is being replaced; any reference in *list* at position *i* will be
leaked.
diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst
index 522c028cfb8d406..0e71d5f0055b189 100644
--- a/Doc/c-api/long.rst
+++ b/Doc/c-api/long.rst
@@ -40,9 +40,11 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
Return a new :c:type:`PyLongObject` object from *v*, or ``NULL`` on failure.
- The current implementation keeps an array of integer objects for all integers
- between ``-5`` and ``256``. When you create an int in that range you actually
- just get back a reference to the existing object.
+ .. impl-detail::
+
+ CPython keeps an array of integer objects for all integers
+ between ``-5`` and ``256``. When you create an int in that range
+ you actually just get back a reference to the existing object.
.. c:function:: PyObject* PyLong_FromUnsignedLong(unsigned long v)
@@ -139,7 +141,17 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
.. versionadded:: 3.13
-.. XXX alias PyLong_AS_LONG (for now)
+.. 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::
@@ -161,6 +173,14 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
.. versionchanged:: 3.10
This function will no longer use :meth:`~object.__int__`.
+ .. c:namespace:: NULL
+
+ .. c:function:: long PyLong_AS_LONG(PyObject *obj)
+
+ Exactly equivalent to the preferred ``PyLong_AsLong``. In particular,
+ it can fail with :exc:`OverflowError` or another exception.
+
+ .. soft-deprecated:: 3.14
.. c:function:: int PyLong_AsInt(PyObject *obj)
@@ -358,6 +378,17 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
Returns ``NULL`` on error. Use :c:func:`PyErr_Occurred` to disambiguate.
+.. 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:: Py_ssize_t PyLong_AsNativeBytes(PyObject *pylong, void* buffer, Py_ssize_t n_bytes, int flags)
Copy the Python integer value *pylong* to a native *buffer* of size
@@ -370,10 +401,10 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
Otherwise, returns the number of bytes required to store the value.
If this is equal to or less than *n_bytes*, the entire value was copied.
- All *n_bytes* of the buffer are written: large buffers are padded with
- zeroes.
+ All *n_bytes* of the buffer are written: remaining bytes filled by
+ copies of the sign bit.
- If the returned value is greater than than *n_bytes*, the value was
+ If the returned value is greater than *n_bytes*, the value was
truncated: as many of the lowest bits of the value as could fit are written,
and the higher bits are ignored. This matches the typical behavior
of a C-style downcast.
@@ -405,14 +436,13 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
Passing zero to *n_bytes* will return the size of a buffer that would
be large enough to hold the value. This may be larger than technically
- necessary, but not unreasonably so.
+ necessary, but not unreasonably so. If *n_bytes=0*, *buffer* may be
+ ``NULL``.
.. note::
Passing *n_bytes=0* to this function is not an accurate way to determine
- the bit length of a value.
-
- If *n_bytes=0*, *buffer* may be ``NULL``.
+ the bit length of the value.
To get at the entire Python value of an unknown size, the function can be
called twice: first to determine the buffer size, then to fill it::
@@ -446,13 +476,15 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
free(bignum);
*flags* is either ``-1`` (``Py_ASNATIVEBYTES_DEFAULTS``) to select defaults
- that behave most like a C cast, or a combintation of the other flags in
+ that behave most like a C cast, or a combination of the other flags in
the table below.
Note that ``-1`` cannot be combined with other flags.
Currently, ``-1`` corresponds to
``Py_ASNATIVEBYTES_NATIVE_ENDIAN | Py_ASNATIVEBYTES_UNSIGNED_BUFFER``.
+ .. c:namespace:: NULL
+
============================================= ======
Flag Value
============================================= ======
@@ -462,6 +494,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
.. c:macro:: Py_ASNATIVEBYTES_NATIVE_ENDIAN ``3``
.. c:macro:: Py_ASNATIVEBYTES_UNSIGNED_BUFFER ``4``
.. c:macro:: Py_ASNATIVEBYTES_REJECT_NEGATIVE ``8``
+ .. c:macro:: Py_ASNATIVEBYTES_ALLOW_INDEX ``16``
============================================= ======
Specifying ``Py_ASNATIVEBYTES_NATIVE_ENDIAN`` will override any other endian
@@ -483,6 +516,13 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
provided there is enough space for at least one sign bit, regardless of
whether ``Py_ASNATIVEBYTES_UNSIGNED_BUFFER`` was specified.
+ If ``Py_ASNATIVEBYTES_ALLOW_INDEX`` is specified and a non-integer value is
+ passed, its :meth:`~object.__index__` method will be called first. This may
+ result in Python code executing and other threads being allowed to run, which
+ could cause changes to other objects or values in use. When *flags* is
+ ``-1``, this option is not set, and non-integer values will raise
+ :exc:`TypeError`.
+
.. note::
With the default *flags* (``-1``, or *UNSIGNED_BUFFER* without
@@ -494,6 +534,17 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
.. versionadded:: 3.13
+.. c:function:: PyObject* PyLong_GetInfo(void)
+
+ On success, return a read only :term:`named tuple`, that holds
+ information about Python's internal representation of integers.
+ See :data:`sys.int_info` for description of individual fields.
+
+ On failure, return ``NULL`` with an exception set.
+
+ .. versionadded:: 3.1
+
+
.. c:function:: int PyUnstable_Long_IsCompact(const PyLongObject* op)
Return 1 if *op* is compact, 0 otherwise.
@@ -509,6 +560,9 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
Exactly what values are considered compact is an implementation detail
and is subject to change.
+ .. versionadded:: 3.12
+
+
.. c:function:: Py_ssize_t PyUnstable_Long_CompactValue(const PyLongObject* op)
If *op* is compact, as determined by :c:func:`PyUnstable_Long_IsCompact`,
@@ -516,3 +570,5 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
Otherwise, the return value is undefined.
+ .. versionadded:: 3.12
+
diff --git a/Doc/c-api/mapping.rst b/Doc/c-api/mapping.rst
index 1f55c0aa955c75b..2476ebb9b69dce0 100644
--- a/Doc/c-api/mapping.rst
+++ b/Doc/c-api/mapping.rst
@@ -102,7 +102,7 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and
.. note::
- Exceptions which occur when this calls :meth:`~object.__getitem__`
+ Exceptions which occur when this calls the :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 :meth:`~object.__getitem__`
+ Exceptions that occur when this calls the :meth:`~object.__getitem__`
method or while creating the temporary :class:`str`
object are silently ignored.
For proper error handling, use :c:func:`PyMapping_HasKeyStringWithError`,
diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst
index 489f1580a414b2d..85145190457fc67 100644
--- a/Doc/c-api/marshal.rst
+++ b/Doc/c-api/marshal.rst
@@ -15,7 +15,7 @@ Numeric values are stored with the least significant byte first.
The module supports two versions of the data format: version 0 is the
historical version, version 1 shares interned strings in the file, and upon
-unmarshalling. Version 2 uses a binary format for floating point numbers.
+unmarshalling. Version 2 uses a binary format for floating-point numbers.
``Py_MARSHAL_VERSION`` indicates the current file format (currently 2).
@@ -81,7 +81,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 these variant if you are certain that you won't be reading
+ file. Only use this 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`
diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst
index 9da09a21607f617..a4fb24b0353a1a5 100644
--- a/Doc/c-api/memory.rst
+++ b/Doc/c-api/memory.rst
@@ -81,7 +81,7 @@ memory footprint as a whole. Consequently, under certain circumstances, the
Python memory manager may or may not trigger appropriate actions, like garbage
collection, memory compaction or other preventive procedures. Note that by using
the C library allocator as shown in the previous example, the allocated memory
-for the I/O buffer escapes completely the Python memory manager.
+for the I/O buffer completely escapes the Python memory manager.
.. seealso::
@@ -102,30 +102,38 @@ 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:`here `. There is no hard
-requirement to use the memory returned by the allocation functions belonging to
-a given domain for only the purposes hinted by that domain (although this is the
-recommended practice). For example, one could use the memory returned by
-:c:func:`PyMem_RawMalloc` for allocating Python objects or the memory returned
-by :c:func:`PyObject_Malloc` for allocating memory for buffers.
+table can be found at :ref:`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`.
The three allocation domains are:
* Raw domain: intended for allocating memory for general-purpose memory
buffers where the allocation *must* go to the system allocator or where the
allocator can operate without the :term:`GIL`. The memory is requested directly
- to the system.
+ from the system. See :ref:`Raw Memory Interface `.
* "Mem" domain: intended for allocating memory for Python buffers and
general-purpose memory buffers where the allocation must be performed with
the :term:`GIL` held. The memory is taken from the Python private heap.
+ See :ref:`Memory Interface `.
-* Object domain: intended for allocating memory belonging to Python objects. The
- memory is taken from the Python private heap.
+* Object domain: intended for allocating memory for Python objects. The
+ memory is taken from the Python private heap. See :ref:`Object allocators `.
-When freeing memory previously allocated by the allocating functions belonging to a
-given domain,the matching specific deallocating functions must be used. For example,
-:c:func:`PyMem_Free` must be used to free memory allocated using :c:func:`PyMem_Malloc`.
+.. note::
+
+ The :term:`free-threaded ` build requires that only Python objects are allocated using the "object" domain
+ and that all Python objects are allocated using that domain. This differs from the prior Python versions,
+ where this was only a best practice and not a hard requirement.
+
+ For example, buffers (non-Python objects) should be allocated using :c:func:`PyMem_Malloc`,
+ :c:func:`PyMem_RawMalloc`, or :c:func:`malloc`, but not :c:func:`PyObject_Malloc`.
+
+ See :ref:`Memory Allocation APIs `.
+
+
+.. _raw-memoryinterface:
Raw Memory Interface
====================
@@ -153,7 +161,7 @@ zero bytes.
.. c:function:: void* PyMem_RawCalloc(size_t nelem, size_t elsize)
- Allocates *nelem* elements each whose size in bytes is *elsize* and returns
+ Allocates *nelem* elements each of size *elsize* bytes and returns
a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the
request fails. The memory is initialized to zeros.
@@ -224,7 +232,7 @@ The :ref:`default memory allocator ` uses the
.. c:function:: void* PyMem_Calloc(size_t nelem, size_t elsize)
- Allocates *nelem* elements each whose size in bytes is *elsize* and returns
+ Allocates *nelem* elements each of size *elsize* bytes and returns
a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the
request fails. The memory is initialized to zeros.
@@ -286,18 +294,42 @@ The following type-oriented macros are provided for convenience. Note that
Same as :c:func:`PyMem_Free`.
-In addition, the following macro sets are provided for calling the Python memory
-allocator directly, without involving the C API functions listed above. However,
-note that their use does not preserve binary compatibility across Python
-versions and is therefore deprecated in extension modules.
-* ``PyMem_MALLOC(size)``
-* ``PyMem_NEW(type, size)``
-* ``PyMem_REALLOC(ptr, size)``
-* ``PyMem_RESIZE(ptr, type, size)``
-* ``PyMem_FREE(ptr)``
-* ``PyMem_DEL(ptr)``
+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
+ * Corresponding function or macro
+ * * .. c:macro:: PyMem_MALLOC(size)
+ * :c:func:`PyMem_Malloc`
+ * * .. c:macro:: PyMem_NEW(type, size)
+ * :c:macro:`PyMem_New`
+ * * .. c:macro:: PyMem_REALLOC(ptr, size)
+ * :c:func:`PyMem_Realloc`
+ * * .. c:macro:: PyMem_RESIZE(ptr, type, size)
+ * :c:macro:`PyMem_Resize`
+ * * .. c:macro:: PyMem_FREE(ptr)
+ * :c:func:`PyMem_Free`
+ * * .. c:macro:: PyMem_DEL(ptr)
+ * :c:func:`PyMem_Free`
+
+.. versionchanged:: 3.4
+
+ The macros are now aliases of the corresponding functions and macros.
+ Previously, their behavior was the same, but their use did not necessarily
+ preserve binary compatibility across Python versions.
+
+.. deprecated:: 2.0
+
+
+.. _objectinterface:
Object allocators
=================
@@ -332,7 +364,7 @@ The :ref:`default object allocator ` uses the
.. c:function:: void* PyObject_Calloc(size_t nelem, size_t elsize)
- Allocates *nelem* elements each whose size in bytes is *elsize* and returns
+ Allocates *nelem* elements each of size *elsize* bytes and returns
a pointer of type :c:expr:`void*` to the allocated memory, or ``NULL`` if the
request fails. The memory is initialized to zeros.
@@ -646,6 +678,10 @@ This allocator is disabled if Python is configured with the
:option:`--without-pymalloc` option. It can also be disabled at runtime using
the :envvar:`PYTHONMALLOC` environment variable (ex: ``PYTHONMALLOC=malloc``).
+Typically, it makes sense to disable the pymalloc allocator when building
+Python with AddressSanitizer (:option:`--with-address-sanitizer`) which helps
+uncover low level bugs within the C code.
+
Customize pymalloc Arena Allocator
----------------------------------
diff --git a/Doc/c-api/memoryview.rst b/Doc/c-api/memoryview.rst
index f6038032805259f..e4ac8b57673407c 100644
--- a/Doc/c-api/memoryview.rst
+++ b/Doc/c-api/memoryview.rst
@@ -13,6 +13,12 @@ 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.
diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst
index 6fe1ce9e9948320..419865180383a56 100644
--- a/Doc/c-api/module.rst
+++ b/Doc/c-api/module.rst
@@ -13,7 +13,7 @@ Module Objects
.. index:: single: ModuleType (in module types)
This instance of :c:type:`PyTypeObject` represents the Python module type. This
- is exposed to Python programs as ``types.ModuleType``.
+ is exposed to Python programs as :py:class:`types.ModuleType`.
.. c:function:: int PyModule_Check(PyObject *p)
@@ -37,16 +37,19 @@ Module Objects
single: __package__ (module attribute)
single: __loader__ (module attribute)
- Return a new module object with the :attr:`__name__` attribute set to *name*.
- The module's :attr:`__name__`, :attr:`__doc__`, :attr:`__package__`, and
- :attr:`__loader__` attributes are filled in (all but :attr:`__name__` are set
- to ``None``); the caller is responsible for providing a :attr:`__file__`
- attribute.
+ Return a new module object with :attr:`module.__name__` set to *name*.
+ The module's :attr:`!__name__`, :attr:`~module.__doc__`,
+ :attr:`~module.__package__` and :attr:`~module.__loader__` attributes are
+ filled in (all but :attr:`!__name__` are set to ``None``). The caller is
+ responsible for setting a :attr:`~module.__file__` attribute.
+
+ Return ``NULL`` with an exception set on error.
.. versionadded:: 3.3
.. versionchanged:: 3.4
- :attr:`__package__` and :attr:`__loader__` are set to ``None``.
+ :attr:`~module.__package__` and :attr:`~module.__loader__` are now set to
+ ``None``.
.. c:function:: PyObject* PyModule_New(const char *name)
@@ -68,6 +71,9 @@ 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)
@@ -75,8 +81,9 @@ Module Objects
single: __name__ (module attribute)
single: SystemError (built-in exception)
- Return *module*'s :attr:`__name__` value. If the module does not provide one,
- or if it is not a string, :exc:`SystemError` is raised and ``NULL`` is returned.
+ Return *module*'s :attr:`~module.__name__` value. If the module does not
+ provide one, or if it is not a string, :exc:`SystemError` is raised and
+ ``NULL`` is returned.
.. versionadded:: 3.3
@@ -86,6 +93,10 @@ 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
@@ -98,6 +109,10 @@ Module Objects
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)
@@ -106,8 +121,8 @@ Module Objects
single: SystemError (built-in exception)
Return the name of the file from which *module* was loaded using *module*'s
- :attr:`__file__` attribute. If this is not defined, or if it is not a
- unicode string, raise :exc:`SystemError` and return ``NULL``; otherwise return
+ :attr:`~module.__file__` attribute. If this is not defined, or if it is not a
+ string, raise :exc:`SystemError` and return ``NULL``; otherwise return
a reference to a Unicode object.
.. versionadded:: 3.2
@@ -118,6 +133,9 @@ 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.
@@ -245,6 +263,12 @@ or request "multi-phase initialization" by returning the definition struct itsel
.. versionchanged:: 3.9
No longer called before the module state is allocated.
+
+.. c:var:: PyTypeObject PyModuleDef_Type
+
+ The type of ``PyModuleDef`` objects.
+
+
Single-phase initialization
...........................
@@ -265,6 +289,8 @@ of the following two module creation functions:
API version *module_api_version*. If that version does not match the version
of the running interpreter, a :exc:`RuntimeWarning` is emitted.
+ Return ``NULL`` with an exception set on error.
+
.. note::
Most uses of this function should be using :c:func:`PyModule_Create`
@@ -282,22 +308,40 @@ An alternate way to specify extensions is to request "multi-phase initialization
Extension modules created this way behave more like Python modules: the
initialization is split between the *creation phase*, when the module object
is created, and the *execution phase*, when it is populated.
-The distinction is similar to the :py:meth:`!__new__` and :py:meth:`!__init__` methods
-of classes.
+The distinction is similar to the :py:meth:`~object.__new__` and
+:py:meth:`~object.__init__` methods of classes.
Unlike modules created using single-phase initialization, these modules are not
-singletons: if the *sys.modules* entry is removed and the module is re-imported,
-a new module object is created, and the old module is subject to normal garbage
-collection -- as with Python modules.
-By default, multiple modules created from the same definition should be
-independent: changes to one should not affect the others.
-This means that all state should be specific to the module object (using e.g.
-using :c:func:`PyModule_GetState`), or its contents (such as the module's
-:attr:`~object.__dict__` or individual classes created with :c:func:`PyType_FromSpec`).
+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
+fresh method and type objects.
+The old module is subject to normal garbage collection.
+This mirrors the behavior of pure-Python modules.
+
+Additional module instances may be created in
+:ref:`sub-interpreters `
+or after after Python runtime reinitialization
+(:c:func:`Py_Finalize` and :c:func:`Py_Initialize`).
+In these cases, sharing Python objects between module instances would likely
+cause crashes or undefined behavior.
+
+To avoid such issues, each instance of an extension module should
+be *isolated*: changes to one instance should not implicitly affect the others,
+and all state, including references to Python objects, should be specific to
+a particular module instance.
+See :ref:`isolating-extensions-howto` for more details and a practical guide.
+
+A simpler way to avoid these issues is
+:ref:`raising an error on repeated initialization `.
All modules created using multi-phase initialization are expected to support
-:ref:`sub-interpreters `. Making sure multiple modules
-are independent is typically enough to achieve this.
+:ref:`sub-interpreters `, or otherwise explicitly
+signal a lack of support.
+This is usually achieved by isolation or blocking repeated initialization,
+as above.
+A module may also be limited to the main interpreter using
+the :c:data:`Py_mod_multiple_interpreters` slot.
To request multi-phase initialization, the initialization function
(PyInit_modulename) returns a :c:type:`PyModuleDef` instance with non-empty
@@ -338,7 +382,8 @@ The available slot types are:
The *value* pointer of this slot must point to a function of the signature:
.. c:function:: PyObject* create_module(PyObject *spec, PyModuleDef *def)
- :noindex:
+ :no-index-entry:
+ :no-contents-entry:
The function receives a :py:class:`~importlib.machinery.ModuleSpec`
instance, as defined in :PEP:`451`, and the module definition.
@@ -365,6 +410,8 @@ The available slot types are:
``PyModuleDef`` has non-``NULL`` ``m_traverse``, ``m_clear``,
``m_free``; non-zero ``m_size``; or slots other than ``Py_mod_create``.
+ .. versionadded:: 3.5
+
.. c:macro:: Py_mod_exec
Specifies a function that is called to *execute* the module.
@@ -373,11 +420,14 @@ The available slot types are:
The signature of the function is:
.. c:function:: int exec_module(PyObject* module)
- :noindex:
+ :no-index-entry:
+ :no-contents-entry:
If multiple ``Py_mod_exec`` slots are specified, they are processed in the
order they appear in the *m_slots* array.
+ .. versionadded:: 3.5
+
.. c:macro:: Py_mod_multiple_interpreters
Specifies one of the following values:
@@ -407,7 +457,7 @@ The available slot types are:
in one module definition.
If ``Py_mod_multiple_interpreters`` is not specified, the import
- machinery defaults to ``Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED``.
+ machinery defaults to ``Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED``.
.. versionadded:: 3.12
@@ -415,6 +465,8 @@ The available slot types are:
Specifies one of the following values:
+ .. c:namespace:: NULL
+
.. c:macro:: Py_MOD_GIL_USED
The module depends on the presence of the global interpreter lock (GIL),
@@ -427,14 +479,14 @@ The available slot types are:
This slot is ignored by Python builds not configured with
:option:`--disable-gil`. Otherwise, it determines whether or not importing
this module will cause the GIL to be automatically enabled. See
- :envvar:`PYTHON_GIL` and :option:`-X gil <-X>` for more detail.
+ :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
+ .. versionadded:: 3.13
See :PEP:`489` for more details on multi-phase initialization.
@@ -461,6 +513,8 @@ objects dynamically. Note that both ``PyModule_FromDefAndSpec`` and
If that version does not match the version of the running interpreter,
a :exc:`RuntimeWarning` is emitted.
+ Return ``NULL`` with an exception set on error.
+
.. note::
Most uses of this function should be using :c:func:`PyModule_FromDefAndSpec`
@@ -481,6 +535,9 @@ objects dynamically. Note that both ``PyModule_FromDefAndSpec`` and
``PyModuleDef``, using either ``PyModule_Create`` or
``PyModule_FromDefAndSpec``.
+ Return ``0`` on success.
+ Return ``-1`` with an exception set on error.
+
.. versionadded:: 3.5
.. c:function:: int PyModule_AddFunctions(PyObject *module, PyMethodDef *functions)
@@ -494,6 +551,9 @@ objects dynamically. Note that both ``PyModule_FromDefAndSpec`` and
``PyModuleDef``, using either ``PyModule_Create`` or
``PyModule_FromDefAndSpec``.
+ The *functions* array must be statically allocated (or otherwise guaranteed
+ to outlive the module object).
+
.. versionadded:: 3.5
Support functions
@@ -511,9 +571,6 @@ state:
On success, return ``0``. On error, raise an exception and return ``-1``.
- Return ``NULL`` if *value* is ``NULL``. It must be called with an exception
- raised in this case.
-
Example usage::
static int
@@ -528,6 +585,10 @@ state:
return res;
}
+ To be convenient, the function accepts ``NULL`` *value* with an exception
+ set. In this case, return ``-1`` and just leave the raised exception
+ unchanged.
+
The example can also be written without checking explicitly if *obj* is
``NULL``::
@@ -543,13 +604,21 @@ state:
Note that ``Py_XDECREF()`` should be used instead of ``Py_DECREF()`` in
this case, since *obj* can be ``NULL``.
+ The number of different *name* strings passed to this function
+ should be kept small, usually by only using statically allocated strings
+ as *name*.
+ For names that aren't known at compile time, prefer calling
+ :c:func:`PyUnicode_FromString` and :c:func:`PyObject_SetAttr` directly.
+ For more details, see :c:func:`PyUnicode_InternFromString`, which may be
+ used internally to create a key object.
+
.. versionadded:: 3.10
.. c:function:: int PyModule_Add(PyObject *module, const char *name, PyObject *value)
- Similar to :c:func:`PyModule_AddObjectRef`, but "steals" a reference
- to *value*.
+ Similar to :c:func:`PyModule_AddObjectRef`, but ":term:`steals `"
+ a reference to *value* (even on error).
It can be called with a result of function that returns a new reference
without bothering to check its result or even saving it to a variable.
@@ -564,8 +633,8 @@ state:
.. c:function:: int PyModule_AddObject(PyObject *module, const char *name, PyObject *value)
- Similar to :c:func:`PyModule_AddObjectRef`, but steals a reference to
- *value* on success (if it returns ``0``).
+ Similar to :c:func:`PyModule_AddObjectRef`, but :term:`steals `
+ a reference to *value* on success (if it returns ``0``).
The new :c:func:`PyModule_Add` or :c:func:`PyModule_AddObjectRef`
functions are recommended, since it is
@@ -593,23 +662,29 @@ state:
// PyModule_AddObject() stole a reference to obj:
// Py_XDECREF(obj) is not needed here.
- .. deprecated:: 3.13
-
- :c:func:`PyModule_AddObject` is :term:`soft deprecated`.
+ .. soft-deprecated:: 3.13
.. c:function:: int PyModule_AddIntConstant(PyObject *module, const char *name, long value)
Add an integer constant to *module* as *name*. This convenience function can be
- used from the module's initialization function. Return ``-1`` on error, ``0`` on
- success.
+ used from the module's initialization function.
+ Return ``-1`` with an exception set on error, ``0`` on success.
+
+ This is a convenience function that calls :c:func:`PyLong_FromLong` and
+ :c:func:`PyModule_AddObjectRef`; see their documentation for details.
.. c:function:: int PyModule_AddStringConstant(PyObject *module, const char *name, const char *value)
Add a string constant to *module* as *name*. This convenience function can be
used from the module's initialization function. The string *value* must be
- ``NULL``-terminated. Return ``-1`` on error, ``0`` on success.
+ ``NULL``-terminated.
+ Return ``-1`` with an exception set on error, ``0`` on success.
+
+ This is a convenience function that calls
+ :c:func:`PyUnicode_InternFromString` and :c:func:`PyModule_AddObjectRef`;
+ see their documentation for details.
.. c:macro:: PyModule_AddIntMacro(module, macro)
@@ -617,7 +692,7 @@ state:
Add an int constant to *module*. The name and the value are taken from
*macro*. For example ``PyModule_AddIntMacro(module, AF_INET)`` adds the int
constant *AF_INET* with the value of *AF_INET* to *module*.
- Return ``-1`` on error, ``0`` on success.
+ Return ``-1`` with an exception set on error, ``0`` on success.
.. c:macro:: PyModule_AddStringMacro(module, macro)
@@ -630,7 +705,7 @@ state:
The type object is finalized by calling internally :c:func:`PyType_Ready`.
The name of the type object is taken from the last component of
:c:member:`~PyTypeObject.tp_name` after dot.
- Return ``-1`` on error, ``0`` on success.
+ Return ``-1`` with an exception set on error, ``0`` on success.
.. versionadded:: 3.9
@@ -643,7 +718,7 @@ state:
import machinery assumes the module does not support running without the
GIL. This function is only available in Python builds configured with
:option:`--disable-gil`.
- Return ``-1`` on error, ``0`` on success.
+ Return ``-1`` with an exception set on error, ``0`` on success.
.. versionadded:: 3.13
@@ -682,14 +757,14 @@ since multiple such modules can be created from a single definition.
The caller must hold the GIL.
- Return 0 on success or -1 on failure.
+ Return ``-1`` with an exception set on error, ``0`` on success.
.. versionadded:: 3.3
.. c:function:: int PyState_RemoveModule(PyModuleDef *def)
Removes the module object created from *def* from the interpreter state.
- Return 0 on success or -1 on failure.
+ Return ``-1`` with an exception set on error, ``0`` on success.
The caller must hold the GIL.
diff --git a/Doc/c-api/monitoring.rst b/Doc/c-api/monitoring.rst
index 763ec8ef761e4eb..c68c32192ad0033 100644
--- a/Doc/c-api/monitoring.rst
+++ b/Doc/c-api/monitoring.rst
@@ -1,8 +1,8 @@
.. highlight:: c
-.. _monitoring:
+.. _c-api-monitoring:
-Monitorong C API
+Monitoring C API
================
Added in version 3.13.
@@ -121,19 +121,19 @@ See :mod:`sys.monitoring` for descriptions of the events.
:c:func:`PyErr_GetRaisedException`).
-.. c:function:: int PyMonitoring_FireStopIterationEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
+.. c:function:: int PyMonitoring_FireStopIterationEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject *value)
- Fire a ``STOP_ITERATION`` event with the current exception (as returned by
- :c:func:`PyErr_GetRaisedException`).
+ Fire a ``STOP_ITERATION`` event. If ``value`` is an instance of :exc:`StopIteration`, it is used. Otherwise,
+ a new :exc:`StopIteration` instance is created with ``value`` as its argument.
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)
+.. c:function:: int PyMonitoring_EnterScope(PyMonitoringState *state_array, uint64_t *version, const uint8_t *event_types, Py_ssize_t length)
Enter a monitored scope. ``event_types`` is an array of the event IDs for
events that may be fired from the scope. For example, the ID of a ``PY_START``
@@ -141,24 +141,62 @@ would typically correspond to a python function.
to the base-2 logarithm of ``sys.monitoring.events.PY_START``.
``state_array`` is an array with a monitoring state entry for each event in
``event_types``, it is allocated by the user but populated by
- ``PyMonitoring_EnterScope`` with information about the activation state of
+ :c:func:`!PyMonitoring_EnterScope` with information about the activation state of
the event. The size of ``event_types`` (and hence also of ``state_array``)
is given in ``length``.
The ``version`` argument is a pointer to a value which should be allocated
by the user together with ``state_array`` and initialized to 0,
- and then set only by ``PyMonitoring_EnterScope`` itelf. It allows this
+ and then set only by :c:func:`!PyMonitoring_EnterScope` itself. It allows this
function to determine whether event states have changed since the previous call,
and to return quickly if they have not.
The scopes referred to here are lexical scopes: a function, class or method.
- ``PyMonitoring_EnterScope`` should be called whenever the lexical scope is
+ :c:func:`!PyMonitoring_EnterScope` should be called whenever the lexical scope is
entered. Scopes can be reentered, reusing the same *state_array* and *version*,
in situations like when emulating a recursive Python function. When a code-like's
execution is paused, such as when emulating a generator, the scope needs to
be exited and re-entered.
+ The macros for *event_types* are:
+
+ .. c:namespace:: NULL
+
+ .. The table is here to make the docs searchable, and to allow automatic
+ links to the identifiers.
+
+ ================================================== =====================================
+ Macro Event
+ ================================================== =====================================
+ .. c:macro:: PY_MONITORING_EVENT_BRANCH :monitoring-event:`BRANCH`
+ .. c:macro:: PY_MONITORING_EVENT_CALL :monitoring-event:`CALL`
+ .. c:macro:: PY_MONITORING_EVENT_C_RAISE :monitoring-event:`C_RAISE`
+ .. c:macro:: PY_MONITORING_EVENT_C_RETURN :monitoring-event:`C_RETURN`
+ .. c:macro:: PY_MONITORING_EVENT_EXCEPTION_HANDLED :monitoring-event:`EXCEPTION_HANDLED`
+ .. c:macro:: PY_MONITORING_EVENT_INSTRUCTION :monitoring-event:`INSTRUCTION`
+ .. c:macro:: PY_MONITORING_EVENT_JUMP :monitoring-event:`JUMP`
+ .. c:macro:: PY_MONITORING_EVENT_LINE :monitoring-event:`LINE`
+ .. c:macro:: PY_MONITORING_EVENT_PY_RESUME :monitoring-event:`PY_RESUME`
+ .. c:macro:: PY_MONITORING_EVENT_PY_RETURN :monitoring-event:`PY_RETURN`
+ .. c:macro:: PY_MONITORING_EVENT_PY_START :monitoring-event:`PY_START`
+ .. c:macro:: PY_MONITORING_EVENT_PY_THROW :monitoring-event:`PY_THROW`
+ .. c:macro:: PY_MONITORING_EVENT_PY_UNWIND :monitoring-event:`PY_UNWIND`
+ .. c:macro:: PY_MONITORING_EVENT_PY_YIELD :monitoring-event:`PY_YIELD`
+ .. c:macro:: PY_MONITORING_EVENT_RAISE :monitoring-event:`RAISE`
+ .. c:macro:: PY_MONITORING_EVENT_RERAISE :monitoring-event:`RERAISE`
+ .. c:macro:: PY_MONITORING_EVENT_STOP_ITERATION :monitoring-event:`STOP_ITERATION`
+ ================================================== =====================================
+
+.. c:function:: int PyMonitoring_ExitScope(void)
+
+ Exit the last scope that was entered with :c:func:`!PyMonitoring_EnterScope`.
+
+
+.. c:function:: int PY_MONITORING_IS_INSTRUMENTED_EVENT(uint8_t ev)
+
+ Return true if the event corresponding to the event ID *ev* is
+ a :ref:`local event `.
-.. :c:function:: int PyMonitoring_ExitScope(void)
+ .. versionadded:: 3.13
- Exit the last scope that was entered with ``PyMonitoring_EnterScope``.
+ .. soft-deprecated:: 3.13.3
diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst
index 13d3c5af956905a..ad8b5935258fa7b 100644
--- a/Doc/c-api/number.rst
+++ b/Doc/c-api/number.rst
@@ -51,8 +51,8 @@ Number Protocol
Return a reasonable approximation for the mathematical value of *o1* divided by
*o2*, or ``NULL`` on failure. The return value is "approximate" because binary
- floating point numbers are approximate; it is not possible to represent all real
- numbers in base two. This function can return a floating point value when
+ floating-point numbers are approximate; it is not possible to represent all real
+ numbers in base two. This function can return a floating-point value when
passed two integers. This is the equivalent of the Python expression ``o1 / o2``.
@@ -177,8 +177,8 @@ Number Protocol
Return a reasonable approximation for the mathematical value of *o1* divided by
*o2*, or ``NULL`` on failure. The return value is "approximate" because binary
- floating point numbers are approximate; it is not possible to represent all real
- numbers in base two. This function can return a floating point value when
+ floating-point numbers are approximate; it is not possible to represent all real
+ numbers in base two. This function can return a floating-point value when
passed two integers. The operation is done *in-place* when *o1* supports it.
This is the equivalent of the Python statement ``o1 /= o2``.
diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst
index ba454db91175042..be4e5847022f33b 100644
--- a/Doc/c-api/object.rst
+++ b/Doc/c-api/object.rst
@@ -52,6 +52,7 @@ Object Protocol
The reference is borrowed from the interpreter, and is valid until the
interpreter finalization.
+
.. versionadded:: 3.13
@@ -65,14 +66,14 @@ Object Protocol
Properly handle returning :c:data:`Py_NotImplemented` from within a C
function (that is, create a new :term:`strong reference`
- to NotImplemented and return it).
+ to :const:`NotImplemented` and return it).
.. c:macro:: Py_PRINT_RAW
Flag to be used with multiple functions that print the object (like
:c:func:`PyObject_Print` and :c:func:`PyFile_WriteObject`).
- If passed, these function would use the :func:`str` of the object
+ If passed, these functions use the :func:`str` of the object
instead of the :func:`repr`.
@@ -84,7 +85,7 @@ Object Protocol
instead of the :func:`repr`.
-.. c:function:: int PyObject_HasAttrWithError(PyObject *o, const char *attr_name)
+.. c:function:: int PyObject_HasAttrWithError(PyObject *o, PyObject *attr_name)
Returns ``1`` if *o* has the attribute *attr_name*, and ``0`` otherwise.
This is equivalent to the Python expression ``hasattr(o, attr_name)``.
@@ -110,7 +111,8 @@ Object Protocol
.. note::
Exceptions that occur when this calls :meth:`~object.__getattr__` and
- :meth:`~object.__getattribute__` methods are silently ignored.
+ :meth:`~object.__getattribute__` methods aren't propagated,
+ but instead given to :func:`sys.unraisablehook`.
For proper error handling, use :c:func:`PyObject_HasAttrWithError`,
:c:func:`PyObject_GetOptionalAttr` or :c:func:`PyObject_GetAttr` instead.
@@ -205,6 +207,13 @@ Object Protocol
If *v* is ``NULL``, the attribute is deleted, but this feature is
deprecated in favour of using :c:func:`PyObject_DelAttrString`.
+ The number of different attribute names passed to this function
+ should be kept small, usually by using a statically allocated string
+ as *attr_name*.
+ For attribute names that aren't known at compile time, prefer calling
+ :c:func:`PyUnicode_FromString` and :c:func:`PyObject_SetAttr` directly.
+ For more details, see :c:func:`PyUnicode_InternFromString`, which may be
+ used internally to create a key object.
.. c:function:: int PyObject_GenericSetAttr(PyObject *o, PyObject *name, PyObject *value)
@@ -230,6 +239,14 @@ Object Protocol
specified as a :c:expr:`const char*` UTF-8 encoded bytes string,
rather than a :c:expr:`PyObject*`.
+ The number of different attribute names passed to this function
+ should be kept small, usually by using a statically allocated string
+ as *attr_name*.
+ For attribute names that aren't known at compile time, prefer calling
+ :c:func:`PyUnicode_FromString` and :c:func:`PyObject_DelAttr` directly.
+ For more details, see :c:func:`PyUnicode_InternFromString`, which may be
+ used internally to create a key object for lookup.
+
.. c:function:: PyObject* PyObject_GenericGetDict(PyObject *o, void *context)
@@ -302,6 +319,8 @@ Object Protocol
representation on success, ``NULL`` on failure. This is the equivalent of the
Python expression ``repr(o)``. Called by the :func:`repr` built-in function.
+ If argument is ``NULL``, return the string ``''``.
+
.. versionchanged:: 3.4
This function now includes a debug assertion to help ensure that it
does not silently discard an active exception.
@@ -316,6 +335,8 @@ Object Protocol
a string similar to that returned by :c:func:`PyObject_Repr` in Python 2.
Called by the :func:`ascii` built-in function.
+ If argument is ``NULL``, return the string ``''``.
+
.. index:: string; PyObject_Str (C function)
@@ -326,6 +347,8 @@ Object Protocol
Python expression ``str(o)``. Called by the :func:`str` built-in function
and, therefore, by the :func:`print` function.
+ If argument is ``NULL``, return the string ``''``.
+
.. versionchanged:: 3.4
This function now includes a debug assertion to help ensure that it
does not silently discard an active exception.
@@ -341,6 +364,8 @@ Object Protocol
a TypeError is raised when *o* is an integer instead of a zero-initialized
bytes object.
+ If argument is ``NULL``, return the :class:`bytes` object ``b''``.
+
.. c:function:: int PyObject_IsSubclass(PyObject *derived, PyObject *cls)
@@ -351,14 +376,14 @@ Object Protocol
The result will be ``1`` when at least one of the checks returns ``1``,
otherwise it will be ``0``.
- If *cls* has a :meth:`~class.__subclasscheck__` method, it will be called to
+ If *cls* has a :meth:`~type.__subclasscheck__` method, it will be called to
determine the subclass status as described in :pep:`3119`. Otherwise,
*derived* is a subclass of *cls* if it is a direct or indirect subclass,
- i.e. contained in ``cls.__mro__``.
+ i.e. contained in :attr:`cls.__mro__ `.
Normally only class objects, i.e. instances of :class:`type` or a derived
class, are considered classes. However, objects can override this by having
- a :attr:`~class.__bases__` attribute (which must be a tuple of base classes).
+ a :attr:`~type.__bases__` attribute (which must be a tuple of base classes).
.. c:function:: int PyObject_IsInstance(PyObject *inst, PyObject *cls)
@@ -370,15 +395,15 @@ Object Protocol
The result will be ``1`` when at least one of the checks returns ``1``,
otherwise it will be ``0``.
- If *cls* has a :meth:`~class.__instancecheck__` method, it will be called to
+ If *cls* has a :meth:`~type.__instancecheck__` method, it will be called to
determine the subclass status as described in :pep:`3119`. Otherwise, *inst*
is an instance of *cls* if its class is a subclass of *cls*.
An instance *inst* can override what is considered its class by having a
- :attr:`~instance.__class__` attribute.
+ :attr:`~object.__class__` attribute.
An object *cls* can override if it is considered a class, and what its base
- classes are, by having a :attr:`~class.__bases__` attribute (which must be a tuple
+ classes are, by having a :attr:`~type.__bases__` attribute (which must be a tuple
of base classes).
@@ -476,6 +501,13 @@ Object Protocol
on failure. This is equivalent to the Python statement ``del o[key]``.
+.. c:function:: int PyObject_DelItemString(PyObject *o, const char *key)
+
+ This is the same as :c:func:`PyObject_DelItem`, but *key* is
+ specified as a :c:expr:`const char*` UTF-8 encoded bytes string,
+ rather than a :c:expr:`PyObject*`.
+
+
.. c:function:: PyObject* PyObject_Dir(PyObject *o)
This is equivalent to the Python expression ``dir(o)``, returning a (possibly
@@ -493,6 +525,12 @@ Object Protocol
iterated.
+.. c:function:: PyObject* PyObject_SelfIter(PyObject *obj)
+
+ This is equivalent to the Python ``__iter__(self): return self`` method.
+ It is intended for :term:`iterator` types, to be used in the :c:member:`PyTypeObject.tp_iter` slot.
+
+
.. c:function:: PyObject* PyObject_GetAIter(PyObject *o)
This is the equivalent to the Python expression ``aiter(o)``. Takes an
@@ -555,7 +593,7 @@ Object Protocol
Clear the managed dictionary of *obj*.
- This function must only be called in a traverse function of the type which
+ This function must only be called in a clear function of the type which
has the :c:macro:`Py_TPFLAGS_MANAGED_DICT` flag set.
.. versionadded:: 3.13
diff --git a/Doc/c-api/perfmaps.rst b/Doc/c-api/perfmaps.rst
index 3d44d2eb6bf41d6..11a00917dfa8c2b 100644
--- a/Doc/c-api/perfmaps.rst
+++ b/Doc/c-api/perfmaps.rst
@@ -48,3 +48,43 @@ Note that holding the Global Interpreter Lock (GIL) is not required for these AP
This is called by the runtime itself during interpreter shut-down. In
general, there shouldn't be a reason to explicitly call this, except to
handle specific scenarios such as forking.
+
+.. c:function:: int PyUnstable_CopyPerfMapFile(const char *parent_filename)
+
+ Open the ``/tmp/perf-$pid.map`` file and append the content of *parent_filename*
+ to it.
+
+ This function is available on all platforms but only generates output on platforms
+ that support perf maps (currently only Linux). On other platforms, it does nothing.
+
+ .. versionadded:: 3.13
+
+.. c:function:: int PyUnstable_PerfTrampoline_CompileCode(PyCodeObject *code)
+
+ Compile the given code object using the current perf trampoline.
+
+ The "current" trampoline is the one set by the runtime or the most recent
+ :c:func:`PyUnstable_PerfTrampoline_SetPersistAfterFork` call.
+
+ If no trampoline is set, falls back to normal compilation (no perf map entry).
+
+ :param code: The code object to compile.
+ :return: 0 on success, -1 on failure.
+
+ .. versionadded:: 3.13
+
+.. c:function:: int PyUnstable_PerfTrampoline_SetPersistAfterFork(int enable)
+
+ Set whether the perf trampoline should persist after a fork.
+
+ * If ``enable`` is true (non-zero): perf map file remains open/valid post-fork.
+ Child process inherits all existing perf map entries.
+ * If ``enable`` is false (zero): perf map closes post-fork.
+ Child process gets empty perf map.
+
+ Default: false (clears on fork).
+
+ :param enable: 1 to enable, 0 to disable.
+ :return: 0 on success, -1 on failure.
+
+ .. versionadded:: 3.13
diff --git a/Doc/c-api/picklebuffer.rst b/Doc/c-api/picklebuffer.rst
new file mode 100644
index 000000000000000..9e2d92341b0f93e
--- /dev/null
+++ b/Doc/c-api/picklebuffer.rst
@@ -0,0 +1,59 @@
+.. 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
+` 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 `.
+
+ 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.
diff --git a/Doc/c-api/refcounting.rst b/Doc/c-api/refcounting.rst
index bf50107347e0e78..524341794d241db 100644
--- a/Doc/c-api/refcounting.rst
+++ b/Doc/c-api/refcounting.rst
@@ -62,7 +62,7 @@ of Python objects.
``NULL``, use :c:func:`Py_XINCREF`.
Do not expect this function to actually modify *o* in any way.
- For at least `some objects `_,
+ For at least :pep:`some objects <0683>`,
this function has no effect.
.. versionchanged:: 3.12
@@ -130,7 +130,7 @@ of Python objects.
use :c:func:`Py_XDECREF`.
Do not expect this function to actually modify *o* in any way.
- For at least `some objects `_,
+ For at least :pep:`some objects <683>`,
this function has no effect.
.. warning::
@@ -201,7 +201,7 @@ of Python objects.
Py_SETREF(dst, src);
- That arranges to set *dst* to *src* _before_ releasing the reference
+ That arranges to set *dst* to *src* *before* releasing the reference
to the old value of *dst*, so that any code triggered as a side-effect
of *dst* getting torn down no longer believes *dst* points
to a valid object.
diff --git a/Doc/c-api/reflection.rst b/Doc/c-api/reflection.rst
index 4b1c4770848a306..038e69771045606 100644
--- a/Doc/c-api/reflection.rst
+++ b/Doc/c-api/reflection.rst
@@ -7,18 +7,48 @@ Reflection
.. c:function:: PyObject* PyEval_GetBuiltins(void)
+ .. deprecated:: 3.13
+
+ Use :c:func:`PyEval_GetFrameBuiltins` instead.
+
Return a dictionary of the builtins in the current execution frame,
or the interpreter of the thread state if no frame is currently executing.
.. c:function:: PyObject* PyEval_GetLocals(void)
- Return a dictionary of the local variables in the current execution frame,
+ .. deprecated:: 3.13
+
+ Use either :c:func:`PyEval_GetFrameLocals` to obtain the same behaviour as calling
+ :func:`locals` in Python code, or else call :c:func:`PyFrame_GetLocals` on the result
+ of :c:func:`PyEval_GetFrame` to access the :attr:`~frame.f_locals` attribute of the
+ currently executing frame.
+
+ Return a mapping providing access to the local variables in the current execution frame,
or ``NULL`` if no frame is currently executing.
+ Refer to :func:`locals` for details of the mapping returned at different scopes.
+
+ As this function returns a :term:`borrowed reference`, the dictionary returned for
+ :term:`optimized scopes ` is cached on the frame object and will remain
+ alive as long as the frame object does. Unlike :c:func:`PyEval_GetFrameLocals` and
+ :func:`locals`, subsequent calls to this function in the same frame will update the
+ contents of the cached dictionary to reflect changes in the state of the local variables
+ rather than returning a new snapshot.
+
+ .. versionchanged:: 3.13
+ As part of :pep:`667`, :c:func:`PyFrame_GetLocals`, :func:`locals`, and
+ :attr:`FrameType.f_locals ` no longer make use of the shared cache
+ dictionary. Refer to the :ref:`What's New entry ` for
+ additional details.
+
.. c:function:: PyObject* PyEval_GetGlobals(void)
+ .. deprecated:: 3.13
+
+ Use :c:func:`PyEval_GetFrameGlobals` instead.
+
Return a dictionary of the global variables in the current execution frame,
or ``NULL`` if no frame is currently executing.
@@ -31,6 +61,36 @@ Reflection
See also :c:func:`PyThreadState_GetFrame`.
+.. c:function:: PyObject* PyEval_GetFrameBuiltins(void)
+
+ Return a dictionary of the builtins in the current execution frame,
+ or the interpreter of the thread state if no frame is currently executing.
+
+ .. versionadded:: 3.13
+
+
+.. c:function:: PyObject* PyEval_GetFrameLocals(void)
+
+ Return a dictionary of the local variables in the current execution frame,
+ or ``NULL`` if no frame is currently executing. Equivalent to calling
+ :func:`locals` in Python code.
+
+ To access :attr:`~frame.f_locals` on the current frame without making an independent
+ snapshot in :term:`optimized scopes `, call :c:func:`PyFrame_GetLocals`
+ on the result of :c:func:`PyEval_GetFrame`.
+
+ .. versionadded:: 3.13
+
+
+.. c:function:: PyObject* PyEval_GetFrameGlobals(void)
+
+ Return a dictionary of the global variables in the current execution frame,
+ or ``NULL`` if no frame is currently executing. Equivalent to calling
+ :func:`globals` in Python code.
+
+ .. versionadded:: 3.13
+
+
.. c:function:: const char* PyEval_GetFuncName(PyObject *func)
Return the name of *func* if it is a function, class or instance object, else the
diff --git a/Doc/c-api/sequence.rst b/Doc/c-api/sequence.rst
index ce28839f5ba739d..465c55b5352d6c3 100644
--- a/Doc/c-api/sequence.rst
+++ b/Doc/c-api/sequence.rst
@@ -67,7 +67,7 @@ Sequence Protocol
Assign object *v* to the *i*\ th element of *o*. Raise an exception
and return ``-1`` on failure; return ``0`` on success. This
is the equivalent of the Python statement ``o[i] = v``. This function *does
- not* steal a reference to *v*.
+ not* ":term:`steal`" a reference to *v*.
If *v* is ``NULL``, the element is deleted, but this feature is
deprecated in favour of using :c:func:`PySequence_DelItem`.
diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst
index cba823aa027bd6d..09c0fb6b9c5f233 100644
--- a/Doc/c-api/set.rst
+++ b/Doc/c-api/set.rst
@@ -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:`~frozenset.discard`
+ :exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~set.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.
diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst
index 27a1757c745d8bf..c6d761fe7fd1c96 100644
--- a/Doc/c-api/slice.rst
+++ b/Doc/c-api/slice.rst
@@ -23,7 +23,9 @@ Slice Objects
Return a new slice object with the given values. The *start*, *stop*, and
*step* parameters are used as the values of the slice object attributes of
the same names. Any of the values may be ``NULL``, in which case the
- ``None`` will be used for the corresponding attribute. Return ``NULL`` if
+ ``None`` will be used for the corresponding attribute.
+
+ Return ``NULL`` with an exception set if
the new object could not be allocated.
@@ -52,7 +54,7 @@ Slice Objects
of bounds indices are clipped in a manner consistent with the handling of
normal slices.
- Returns ``0`` on success and ``-1`` on error with exception set.
+ Return ``0`` on success and ``-1`` on error with an exception set.
.. note::
This function is considered not safe for resizable sequences.
@@ -95,7 +97,7 @@ Slice Objects
``PY_SSIZE_T_MIN`` to ``PY_SSIZE_T_MIN``, and silently boost the step
values less than ``-PY_SSIZE_T_MAX`` to ``-PY_SSIZE_T_MAX``.
- Return ``-1`` on error, ``0`` on success.
+ Return ``-1`` with an exception set on error, ``0`` on success.
.. versionadded:: 3.6.1
@@ -116,6 +118,12 @@ Ellipsis Object
^^^^^^^^^^^^^^^
+.. c:var:: PyTypeObject PyEllipsis_Type
+
+ The type of Python :const:`Ellipsis` object. Same as :class:`types.EllipsisType`
+ in the Python layer.
+
+
.. c:var:: PyObject *Py_Ellipsis
The Python ``Ellipsis`` object. This object has no methods. Like
diff --git a/Doc/c-api/stable.rst b/Doc/c-api/stable.rst
index 5b9e43874c7f2ba..124e58cf950b7a7 100644
--- a/Doc/c-api/stable.rst
+++ b/Doc/c-api/stable.rst
@@ -66,7 +66,7 @@ Limited C API
Python 3.2 introduced the *Limited API*, a subset of Python's C API.
Extensions that only use the Limited API can be
-compiled once and work with multiple versions of Python.
+compiled once and be loaded on multiple versions of Python.
Contents of the Limited API are :ref:`listed below `.
.. c:macro:: Py_LIMITED_API
@@ -76,7 +76,7 @@ Contents of the Limited API are :ref:`listed below `.
Define ``Py_LIMITED_API`` to the value of :c:macro:`PY_VERSION_HEX`
corresponding to the lowest Python version your extension supports.
- The extension will work without recompilation with all Python 3 releases
+ The extension will be ABI-compatible with all Python 3 releases
from the specified one onward, and can use Limited API introduced up to that
version.
@@ -94,7 +94,15 @@ Stable ABI
----------
To enable this, Python provides a *Stable ABI*: a set of symbols that will
-remain compatible across Python 3.x versions.
+remain ABI-compatible across Python 3.x versions.
+
+.. note::
+
+ The Stable ABI prevents ABI issues, like linker errors due to missing
+ symbols or data corruption due to changes in structure layouts or function
+ signatures.
+ However, other changes in Python can change the *behavior* of extensions.
+ See Python's Backwards Compatibility Policy (:pep:`387`) for details.
The Stable ABI contains symbols exposed in the :ref:`Limited API
`, but also other ones – for example, functions necessary to
diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst
index f9461ab01f60492..76cf16e2cb083a5 100644
--- a/Doc/c-api/structures.rst
+++ b/Doc/c-api/structures.rst
@@ -63,6 +63,11 @@ under :ref:`reference counting `.
See documentation of :c:type:`PyVarObject` above.
+.. c:var:: PyTypeObject PyBaseObject_Type
+
+ The base class of all other objects, the same as :class:`object` in Python.
+
+
.. c:function:: int Py_Is(PyObject *x, PyObject *y)
Test if the *x* object is the *y* object, the same as ``x is y`` in Python.
@@ -360,7 +365,7 @@ There are these calling conventions:
These two constants are not used to indicate the calling convention but the
-binding when use with methods of classes. These may not be used for functions
+binding when used with methods of classes. These may not be used for functions
defined for modules. At most one of these flags may be set for any given
method.
@@ -371,8 +376,8 @@ method.
The method will be passed the type object as the first parameter rather
than an instance of the type. This is used to create *class methods*,
- similar to what is created when using the :func:`classmethod` built-in
- function.
+ similar to what is created when using the :deco:`classmethod` built-in
+ decorator.
.. c:macro:: METH_STATIC
@@ -381,7 +386,7 @@ method.
The method will be passed ``NULL`` as the first parameter rather than an
instance of the type. This is used to create *static methods*, similar to
- what is created when using the :func:`staticmethod` built-in function.
+ what is created when using the :deco:`staticmethod` built-in decorator.
One other constant controls whether a method is loaded in place of another
definition with the same method name.
@@ -399,6 +404,25 @@ 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.
@@ -424,6 +448,24 @@ 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)``.
@@ -434,6 +476,62 @@ 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
---------------------------------------
diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst
index d6fca1a0b0a219c..8fb30a7826d84a5 100644
--- a/Doc/c-api/sys.rst
+++ b/Doc/c-api/sys.rst
@@ -123,6 +123,24 @@ 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 attached thread state.
+
+
.. c:function:: wchar_t* Py_DecodeLocale(const char* arg, size_t *size)
.. warning::
@@ -426,3 +444,7 @@ Process Control
function registered last is called first. Each cleanup function will be called
at most once. Since Python's internal finalization will have completed before
the cleanup function, no Python APIs should be called by *func*.
+
+ .. seealso::
+
+ :c:func:`PyUnstable_AtExit` for passing a ``void *data`` argument.
diff --git a/Doc/c-api/time.rst b/Doc/c-api/time.rst
index 5cfdef71b3e191e..7032cc48aa69139 100644
--- a/Doc/c-api/time.rst
+++ b/Doc/c-api/time.rst
@@ -1,5 +1,7 @@
.. highlight:: c
+.. _c-api-time:
+
PyTime C API
============
diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst
index 0d68a360f347f85..6b4d08e6bff223b 100644
--- a/Doc/c-api/tuple.rst
+++ b/Doc/c-api/tuple.rst
@@ -33,12 +33,14 @@ Tuple Objects
.. c:function:: PyObject* PyTuple_New(Py_ssize_t len)
- Return a new tuple object of size *len*, or ``NULL`` on failure.
+ Return a new tuple object of size *len*,
+ or ``NULL`` with an exception set on failure.
.. c:function:: PyObject* PyTuple_Pack(Py_ssize_t n, ...)
- Return a new tuple object of size *n*, or ``NULL`` on failure. The tuple values
+ Return a new tuple object of size *n*,
+ or ``NULL`` with an exception set on failure. The tuple values
are initialized to the subsequent *n* C arguments pointing to Python objects.
``PyTuple_Pack(2, a, b)`` is equivalent to ``Py_BuildValue("(OO)", a, b)``.
@@ -46,12 +48,12 @@ 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.
.. c:function:: Py_ssize_t PyTuple_GET_SIZE(PyObject *p)
- Return the size of the tuple *p*, which must be non-``NULL`` and point to a tuple;
- no error checking is performed.
+ Like :c:func:`PyTuple_Size`, but without error checking.
.. c:function:: PyObject* PyTuple_GetItem(PyObject *p, Py_ssize_t pos)
@@ -74,8 +76,10 @@ Tuple Objects
.. c:function:: PyObject* PyTuple_GetSlice(PyObject *p, Py_ssize_t low, Py_ssize_t high)
Return the slice of the tuple pointed to by *p* between *low* and *high*,
- or ``NULL`` on failure. This is the equivalent of the Python expression
- ``p[low:high]``. Indexing from the end of the tuple is not supported.
+ or ``NULL`` with an exception set on failure.
+
+ This is the equivalent of the Python expression ``p[low:high]``.
+ Indexing from the end of the tuple is not supported.
.. c:function:: int PyTuple_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o)
@@ -86,8 +90,9 @@ Tuple Objects
.. note::
- This function "steals" a reference to *o* and discards a reference to
- an item already in the tuple at the affected position.
+ This function ":term:`steals `" a reference to *o* and discards
+ a reference to an item already in the tuple at the affected position
+ (unless it was NULL).
.. c:function:: void PyTuple_SET_ITEM(PyObject *p, Py_ssize_t pos, PyObject *o)
@@ -100,7 +105,7 @@ Tuple Objects
.. note::
- This function "steals" a reference to *o*, and, unlike
+ This function ":term:`steals `" a reference to *o*, and, unlike
:c:func:`PyTuple_SetItem`, does *not* discard a reference to any item that
is being replaced; any reference in the tuple at position *pos* will be
leaked.
@@ -135,6 +140,8 @@ type.
Create a new struct sequence type from the data in *desc*, described below. Instances
of the resulting type can be created with :c:func:`PyStructSequence_New`.
+ Return ``NULL`` with an exception set on failure.
+
.. c:function:: void PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
@@ -143,8 +150,8 @@ type.
.. c:function:: int PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
- The same as ``PyStructSequence_InitType``, but returns ``0`` on success and ``-1`` on
- failure.
+ Like :c:func:`PyStructSequence_InitType`, but returns ``0`` on success
+ and ``-1`` with an exception set on failure.
.. versionadded:: 3.4
@@ -155,7 +162,8 @@ type.
.. c:member:: const char *name
- Name of the struct sequence type.
+ Fully qualified name of the type; null-terminated UTF-8 encoded.
+ The name must contain the module name.
.. c:member:: const char *doc
@@ -201,6 +209,8 @@ type.
Creates an instance of *type*, which must have been created with
:c:func:`PyStructSequence_NewType`.
+ Return ``NULL`` with an exception set on failure.
+
.. c:function:: PyObject* PyStructSequence_GetItem(PyObject *p, Py_ssize_t pos)
@@ -229,7 +239,7 @@ type.
.. note::
- This function "steals" a reference to *o*.
+ This function ":term:`steals `" a reference to *o*.
.. c:function:: void PyStructSequence_SET_ITEM(PyObject *p, Py_ssize_t *pos, PyObject *o)
diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst
index 0cae5c09505ebe1..065625a4fe51066 100644
--- a/Doc/c-api/type.rst
+++ b/Doc/c-api/type.rst
@@ -53,7 +53,8 @@ Type Objects
.. c:function:: PyObject* PyType_GetDict(PyTypeObject* type)
Return the type object's internal namespace, which is otherwise only
- exposed via a read-only proxy (``cls.__dict__``). This is a
+ exposed via a read-only proxy (:attr:`cls.__dict__ `).
+ This is a
replacement for accessing :c:member:`~PyTypeObject.tp_dict` directly.
The returned dictionary must be treated as read-only.
@@ -81,6 +82,9 @@ Type Objects
error (e.g. no more watcher IDs available), return ``-1`` and set an
exception.
+ In free-threaded builds, :c:func:`PyType_AddWatcher` is not thread-safe,
+ so it must be called at start up (before spawning the first thread).
+
.. versionadded:: 3.12
@@ -112,6 +116,20 @@ 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.
@@ -129,6 +147,18 @@ 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 `.
+ 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
@@ -140,7 +170,7 @@ Type Objects
Return true if *a* is a subtype of *b*.
This function only checks for actual subtypes, which means that
- :meth:`~class.__subclasscheck__` is not called on *b*. Call
+ :meth:`~type.__subclasscheck__` is not called on *b*. Call
:c:func:`PyObject_IsSubclass` to do the same check that :func:`issubclass`
would do.
@@ -151,11 +181,13 @@ Type Objects
Python's default memory allocation mechanism to allocate a new instance and
initialize all its contents to ``NULL``.
+
.. c:function:: PyObject* PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
Generic handler for the :c:member:`~PyTypeObject.tp_new` slot of a type object. Create a
new instance using the type's :c:member:`~PyTypeObject.tp_alloc` slot.
+
.. c:function:: int PyType_Ready(PyTypeObject *type)
Finalize a type object. This should be called on all type objects to finish
@@ -172,34 +204,39 @@ 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 ``__name__`` attribute.
+ Return the type's name. Equivalent to getting the type's
+ :attr:`~type.__name__` attribute.
.. versionadded:: 3.11
+
.. c:function:: PyObject* PyType_GetQualName(PyTypeObject *type)
Return the type's qualified name. Equivalent to getting the
- type's ``__qualname__`` attribute.
+ type's :attr:`~type.__qualname__` attribute.
.. versionadded:: 3.11
.. c:function:: PyObject* PyType_GetFullyQualifiedName(PyTypeObject *type)
Return the type's fully qualified name. Equivalent to
- ``f"{type.__module__}.{type.__qualname__}"``, or ``type.__qualname__`` if
- ``type.__module__`` is not a string or is equal to ``"builtins"``.
+ ``f"{type.__module__}.{type.__qualname__}"``, or :attr:`type.__qualname__`
+ if :attr:`type.__module__` is not a string or is equal to ``"builtins"``.
.. versionadded:: 3.13
+
.. c:function:: PyObject* PyType_GetModuleName(PyTypeObject *type)
- Return the type's module name. Equivalent to getting the ``type.__module__``
- attribute.
+ Return the type's module name. Equivalent to getting the
+ :attr:`type.__module__` attribute.
.. versionadded:: 3.13
+
.. c:function:: void* PyType_GetSlot(PyTypeObject *type, int slot)
Return the function pointer stored in the given slot. If the
@@ -216,11 +253,16 @@ Type Objects
:c:func:`PyType_GetSlot` can now accept all types.
Previously, it was limited to :ref:`heap types `.
+
.. c:function:: PyObject* PyType_GetModule(PyTypeObject *type)
Return the module object associated with the given type when the type was
created using :c:func:`PyType_FromModuleAndSpec`.
+ The returned reference is :term:`borrowed ` from *type*,
+ and will be valid as long as you hold a reference to *type*.
+ Do not release it with :c:func:`Py_DECREF` or similar.
+
If no module is associated with the given type, sets :py:class:`TypeError`
and returns ``NULL``.
@@ -235,6 +277,7 @@ Type Objects
.. versionadded:: 3.9
+
.. c:function:: void* PyType_GetModuleState(PyTypeObject *type)
Return the state of the module object associated with the given type.
@@ -249,6 +292,7 @@ Type Objects
.. versionadded:: 3.9
+
.. c:function:: PyObject* PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
Find the first superclass whose module was created from
@@ -262,8 +306,13 @@ Type Objects
and other places where a method's defining class cannot be passed using the
:c:type:`PyCMethod` calling convention.
+ The returned reference is :term:`borrowed ` 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 PyUnstable_Type_AssignVersionTag(PyTypeObject *type)
Attempt to assign a version tag to the given type.
@@ -274,6 +323,16 @@ 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
.............................
@@ -326,6 +385,7 @@ 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)``.
@@ -348,6 +408,7 @@ The following functions and structs are used to create
:c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it
will be no longer allowed.
+
.. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
Equivalent to ``PyType_FromMetaclass(NULL, NULL, spec, bases)``.
@@ -365,6 +426,7 @@ The following functions and structs are used to create
:c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it
will be no longer allowed.
+
.. c:function:: PyObject* PyType_FromSpec(PyType_Spec *spec)
Equivalent to ``PyType_FromMetaclass(NULL, NULL, spec, NULL)``.
@@ -410,6 +472,9 @@ The following functions and structs are used to create
class need *in addition* to the superclass.
Use :c:func:`PyObject_GetTypeData` to get a pointer to subclass-specific
memory reserved this way.
+ For negative :c:member:`!basicsize`, Python will insert padding when
+ needed to meet :c:member:`~PyTypeObject.tp_basicsize`'s alignment
+ requirements.
.. versionchanged:: 3.12
@@ -429,7 +494,7 @@ The following functions and structs are used to create
in the following situations:
- The base is not variable-sized (its
- :c:member:`~PyTypeObject.tp_itemsize`).
+ :c:member:`~PyTypeObject.tp_itemsize` is zero).
- The requested :c:member:`PyType_Spec.basicsize` is positive,
suggesting that the memory layout of the base class is known.
- The requested :c:member:`PyType_Spec.basicsize` is zero,
@@ -478,19 +543,19 @@ The following functions and structs are used to create
The following “offset” fields cannot be set using :c:type:`PyType_Slot`:
- * :c:member:`~PyTypeObject.tp_weaklistoffset`
- (use :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` instead if possible)
- * :c:member:`~PyTypeObject.tp_dictoffset`
- (use :c:macro:`Py_TPFLAGS_MANAGED_DICT` instead if possible)
- * :c:member:`~PyTypeObject.tp_vectorcall_offset`
- (use ``"__vectorcalloffset__"`` in
- :ref:`PyMemberDef `)
+ * :c:member:`~PyTypeObject.tp_weaklistoffset`
+ (use :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` instead if possible)
+ * :c:member:`~PyTypeObject.tp_dictoffset`
+ (use :c:macro:`Py_TPFLAGS_MANAGED_DICT` instead if possible)
+ * :c:member:`~PyTypeObject.tp_vectorcall_offset`
+ (use ``"__vectorcalloffset__"`` in
+ :ref:`PyMemberDef `)
- 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:member:`Py_tp_members `.
- See :ref:`PyMemberDef documentation `
- for details.
+ 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:member:`Py_tp_members `.
+ See :ref:`PyMemberDef documentation `
+ for details.
The following fields cannot be set at all when creating a heap type:
@@ -510,14 +575,13 @@ The following functions and structs are used to create
To avoid issues, use the *bases* argument of
:c:func:`PyType_FromSpecWithBases` instead.
- .. versionchanged:: 3.9
-
- Slots in :c:type:`PyBufferProcs` may be set in the unlimited API.
+ .. versionchanged:: 3.9
+ Slots in :c:type:`PyBufferProcs` may be set in the unlimited API.
- .. versionchanged:: 3.11
- :c:member:`~PyBufferProcs.bf_getbuffer` and
- :c:member:`~PyBufferProcs.bf_releasebuffer` are now available
- under the :ref:`limited API `.
+ .. versionchanged:: 3.11
+ :c:member:`~PyBufferProcs.bf_getbuffer` and
+ :c:member:`~PyBufferProcs.bf_releasebuffer` are now available
+ under the :ref:`limited API `.
.. c:member:: void *pfunc
diff --git a/Doc/c-api/typehints.rst b/Doc/c-api/typehints.rst
index 98fe68737deb81c..ec2fba6da8b0438 100644
--- a/Doc/c-api/typehints.rst
+++ b/Doc/c-api/typehints.rst
@@ -31,7 +31,7 @@ two types exist -- :ref:`GenericAlias ` and
static PyMethodDef my_obj_methods[] = {
// Other methods.
...
- {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, "See PEP 585"}
+ {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, "my_obj is generic over its contained type"}
...
}
diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst
index a6a2c437ea4e16e..561f95cb90a1778 100644
--- a/Doc/c-api/typeobj.rst
+++ b/Doc/c-api/typeobj.rst
@@ -2,8 +2,8 @@
.. _type-structs:
-Type Objects
-============
+Type Object Structures
+======================
Perhaps one of the most important structures of the Python object system is the
structure that defines a new type: the :c:type:`PyTypeObject` structure. Type
@@ -79,7 +79,7 @@ Quick Reference
| :c:member:`~PyTypeObject.tp_setattro` | :c:type:`setattrofunc` | __setattr__, | X | X | | G |
| | | __delattr__ | | | | |
+------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
- | :c:member:`~PyTypeObject.tp_as_buffer` | :c:type:`PyBufferProcs` * | | | | | % |
+ | :c:member:`~PyTypeObject.tp_as_buffer` | :c:type:`PyBufferProcs` * | :ref:`sub-slots` | | | | % |
+------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
| :c:member:`~PyTypeObject.tp_flags` | unsigned long | | X | X | | ? |
+------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
@@ -325,9 +325,10 @@ sub-slots
+---------------------------------------------------------+-----------------------------------+---------------+
| |
+---------------------------------------------------------+-----------------------------------+---------------+
- | :c:member:`~PyBufferProcs.bf_getbuffer` | :c:func:`getbufferproc` | |
+ | :c:member:`~PyBufferProcs.bf_getbuffer` | :c:func:`getbufferproc` | __buffer__ |
+---------------------------------------------------------+-----------------------------------+---------------+
- | :c:member:`~PyBufferProcs.bf_releasebuffer` | :c:func:`releasebufferproc` | |
+ | :c:member:`~PyBufferProcs.bf_releasebuffer` | :c:func:`releasebufferproc` | __release_\ |
+ | | | buffer\__ |
+---------------------------------------------------------+-----------------------------------+---------------+
.. _slot-typedefs-table:
@@ -355,7 +356,7 @@ slot typedefs
+-----------------------------+-----------------------------+----------------------+
| :c:type:`newfunc` | .. line-block:: | :c:type:`PyObject` * |
| | | |
-| | :c:type:`PyObject` * | |
+| | :c:type:`PyTypeObject` * | |
| | :c:type:`PyObject` * | |
| | :c:type:`PyObject` * | |
+-----------------------------+-----------------------------+----------------------+
@@ -473,7 +474,7 @@ PyTypeObject Definition
-----------------------
The structure definition for :c:type:`PyTypeObject` can be found in
-:file:`Include/object.h`. For convenience of reference, this repeats the
+:file:`Include/cpython/object.h`. For convenience of reference, this repeats the
definition found there:
.. XXX Drop this?
@@ -537,6 +538,9 @@ PyVarObject Slots
initialized to zero. For :ref:`dynamically allocated type objects
`, this field has a special internal meaning.
+ This field should be accessed using the :c:func:`Py_SIZE()` and
+ :c:func:`Py_SET_SIZE()` macros.
+
**Inheritance:**
This field is not inherited by subtypes.
@@ -567,12 +571,12 @@ and :c:data:`PyType_Type` effectively act as defaults.)
For :ref:`statically allocated type objects `,
the *tp_name* field should contain a dot.
- Everything before the last dot is made accessible as the :attr:`__module__`
+ Everything before the last dot is made accessible as the :attr:`~type.__module__`
attribute, and everything after the last dot is made accessible as the
- :attr:`~definition.__name__` attribute.
+ :attr:`~type.__name__` attribute.
If no dot is present, the entire :c:member:`~PyTypeObject.tp_name` field is made accessible as the
- :attr:`~definition.__name__` attribute, and the :attr:`__module__` attribute is undefined
+ :attr:`~type.__name__` attribute, and the :attr:`~type.__module__` attribute is undefined
(unless explicitly set in the dictionary, as explained above). This means your
type will be impossible to pickle. Additionally, it will not be listed in
module documentations created with pydoc.
@@ -587,53 +591,92 @@ and :c:data:`PyType_Type` effectively act as defaults.)
.. c:member:: Py_ssize_t PyTypeObject.tp_basicsize
- Py_ssize_t PyTypeObject.tp_itemsize
+ Py_ssize_t PyTypeObject.tp_itemsize
These fields allow calculating the size in bytes of instances of the type.
There are two kinds of types: types with fixed-length instances have a zero
- :c:member:`~PyTypeObject.tp_itemsize` field, types with variable-length instances have a non-zero
- :c:member:`~PyTypeObject.tp_itemsize` field. For a type with fixed-length instances, all
- instances have the same size, given in :c:member:`~PyTypeObject.tp_basicsize`.
+ :c:member:`!tp_itemsize` field, types with variable-length instances have a non-zero
+ :c:member:`!tp_itemsize` field. For a type with fixed-length instances, all
+ instances have the same size, given in :c:member:`!tp_basicsize`.
+ (Exceptions to this rule can be made using
+ :c:func:`PyUnstable_Object_GC_NewWithExtraData`.)
For a type with variable-length instances, the instances must have an
- :c:member:`~PyVarObject.ob_size` field, and the instance size is :c:member:`~PyTypeObject.tp_basicsize` plus N
- times :c:member:`~PyTypeObject.tp_itemsize`, where N is the "length" of the object. The value of
- N is typically stored in the instance's :c:member:`~PyVarObject.ob_size` field. There are
- exceptions: for example, ints use a negative :c:member:`~PyVarObject.ob_size` to indicate a
- negative number, and N is ``abs(ob_size)`` there. Also, the presence of an
- :c:member:`~PyVarObject.ob_size` field in the instance layout doesn't mean that the instance
- structure is variable-length (for example, the structure for the list type has
- fixed-length instances, yet those instances have a meaningful :c:member:`~PyVarObject.ob_size`
- field).
-
- The basic size includes the fields in the instance declared by the macro
- :c:macro:`PyObject_HEAD` or :c:macro:`PyObject_VAR_HEAD` (whichever is used to
- declare the instance struct) and this in turn includes the :c:member:`~PyObject._ob_prev` and
- :c:member:`~PyObject._ob_next` fields if they are present. This means that the only correct
- way to get an initializer for the :c:member:`~PyTypeObject.tp_basicsize` is to use the
- ``sizeof`` operator on the struct used to declare the instance layout.
- The basic size does not include the GC header size.
+ :c:member:`~PyVarObject.ob_size` field, and the instance size is
+ :c:member:`!tp_basicsize` plus N times :c:member:`!tp_itemsize`,
+ where N is the "length" of the object.
+
+ Functions like :c:func:`PyObject_NewVar` will take the value of N as an
+ argument, and store in the instance's :c:member:`~PyVarObject.ob_size` field.
+ Note that the :c:member:`~PyVarObject.ob_size` field may later be used for
+ other purposes. For example, :py:type:`int` instances use the bits of
+ :c:member:`~PyVarObject.ob_size` in an implementation-defined way.
- A note about alignment: if the variable items require a particular alignment,
- this should be taken care of by the value of :c:member:`~PyTypeObject.tp_basicsize`. Example:
- suppose a type implements an array of ``double``. :c:member:`~PyTypeObject.tp_itemsize` is
- ``sizeof(double)``. It is the programmer's responsibility that
- :c:member:`~PyTypeObject.tp_basicsize` is a multiple of ``sizeof(double)`` (assuming this is the
- alignment requirement for ``double``).
+ .. note::
- For any type with variable-length instances, this field must not be ``NULL``.
+ The :c:member:`~PyVarObject.ob_size` field should be accessed using
+ the :c:func:`Py_SIZE()` and :c:func:`Py_SET_SIZE()` macros.
+
+ Also, the presence of an :c:member:`~PyVarObject.ob_size` field in the
+ instance layout doesn't mean that the instance structure is variable-length.
+ For example, the :py:type:`list` type has fixed-length instances, yet those
+ instances have a :c:member:`~PyVarObject.ob_size` field.
+ (As with :py:type:`int`, avoid reading lists' :c:member:`!ob_size` directly.
+ Call :c:func:`PyList_Size` instead.)
+
+ The :c:member:`!tp_basicsize` includes size needed for data of the type's
+ :c:member:`~PyTypeObject.tp_base`, plus any extra data needed
+ by each instance.
+
+ The correct way to set :c:member:`!tp_basicsize` is to use the
+ ``sizeof`` operator on the struct used to declare the instance layout.
+ This struct must include the struct used to declare the base type.
+ In other words, :c:member:`!tp_basicsize` must be greater than or equal
+ to the base's :c:member:`!tp_basicsize`.
+
+ Since every type is a subtype of :py:type:`object`, this struct must
+ include :c:type:`PyObject` or :c:type:`PyVarObject` (depending on
+ whether :c:member:`~PyVarObject.ob_size` should be included). These are
+ usually defined by the macro :c:macro:`PyObject_HEAD` or
+ :c:macro:`PyObject_VAR_HEAD`, respectively.
+
+ The basic size does not include the GC header size, as that header is not
+ part of :c:macro:`PyObject_HEAD`.
+
+ For cases where struct used to declare the base type is unknown,
+ see :c:member:`PyType_Spec.basicsize` and :c:func:`PyType_FromMetaclass`.
+
+ Notes about alignment:
+
+ - :c:member:`!tp_basicsize` must be a multiple of ``_Alignof(PyObject)``.
+ When using ``sizeof`` on a ``struct`` that includes
+ :c:macro:`PyObject_HEAD`, as recommended, the compiler ensures this.
+ When not using a C ``struct``, or when using compiler
+ extensions like ``__attribute__((packed))``, it is up to you.
+ - If the variable items require a particular alignment,
+ :c:member:`!tp_basicsize` and :c:member:`!tp_itemsize` must each be a
+ multiple of that alignment.
+ For example, if a type's variable part stores a ``double``, it is
+ your responsibility that both fields are a multiple of
+ ``_Alignof(double)``.
**Inheritance:**
- These fields are inherited separately by subtypes. If the base type has a
- non-zero :c:member:`~PyTypeObject.tp_itemsize`, it is generally not safe to set
+ These fields are inherited separately by subtypes.
+ (That is, if the field is set to zero, :c:func:`PyType_Ready` will copy
+ the value from the base type, indicating that the instances do not
+ need additional storage.)
+
+ If the base type has a non-zero :c:member:`~PyTypeObject.tp_itemsize`, it is generally not safe to set
:c:member:`~PyTypeObject.tp_itemsize` to a different non-zero value in a subtype (though this
depends on the implementation of the base type).
.. c:member:: destructor PyTypeObject.tp_dealloc
+ .. corresponding-type-slot:: Py_tp_dealloc
+
A pointer to the instance destructor function. This function must be defined
unless the type guarantees that its instances will never be deallocated (as is
the case for the singletons ``None`` and ``Ellipsis``). The function signature is::
@@ -682,6 +725,19 @@ and :c:data:`PyType_Type` effectively act as defaults.)
Py_DECREF(tp);
}
+ .. warning::
+
+ In a garbage collected Python, :c:member:`!tp_dealloc` may be called from
+ any Python thread, not just the thread which created the object (if the
+ object becomes part of a refcount cycle, that cycle might be collected by
+ a garbage collection on any thread). This is not a problem for Python
+ API calls, since the thread on which :c:member:`!tp_dealloc` is called
+ will own the Global Interpreter Lock (GIL). However, if the object being
+ destroyed in turn destroys objects from some other C or C++ library, care
+ should be taken to ensure that destroying those objects on the thread
+ which called :c:member:`!tp_dealloc` will not violate any assumptions of
+ the library.
+
**Inheritance:**
@@ -735,6 +791,8 @@ 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
@@ -752,6 +810,8 @@ 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
@@ -784,6 +844,8 @@ 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
@@ -849,6 +911,8 @@ 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
@@ -890,6 +954,8 @@ 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`::
@@ -903,6 +969,8 @@ 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
@@ -928,6 +996,8 @@ 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`::
@@ -952,6 +1022,8 @@ 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`::
@@ -1131,7 +1203,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
.. c:macro:: Py_TPFLAGS_MANAGED_DICT
- This bit indicates that instances of the class have a ``__dict__``
+ 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` should also be set.
@@ -1192,8 +1264,8 @@ and :c:data:`PyType_Type` effectively act as defaults.)
.. c:macro:: Py_TPFLAGS_BASE_EXC_SUBCLASS
.. c:macro:: Py_TPFLAGS_TYPE_SUBCLASS
- These flags are used by functions such as
- :c:func:`PyLong_Check` to quickly determine if a type is a 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
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`
@@ -1214,6 +1286,9 @@ and :c:data:`PyType_Type` effectively act as defaults.)
type structure.
+ .. c:macro:: _Py_TPFLAGS_HAVE_VECTORCALL
+ :no-typesetting:
+
.. c:macro:: Py_TPFLAGS_HAVE_VECTORCALL
This bit is set when the class implements
@@ -1225,7 +1300,12 @@ and :c:data:`PyType_Type` effectively act as defaults.)
This bit is inherited if :c:member:`~PyTypeObject.tp_call` is also
inherited.
- .. versionadded:: 3.9
+ .. versionadded:: 3.8 as ``_Py_TPFLAGS_HAVE_VECTORCALL``
+
+ .. versionchanged:: 3.9
+
+ Renamed to the current name, without the leading underscore.
+ The old provisional name is :term:`soft deprecated`.
.. versionchanged:: 3.12
@@ -1328,15 +1408,63 @@ and :c:data:`PyType_Type` effectively act as defaults.)
To indicate that a class has changed call :c:func:`PyType_Modified`
.. warning::
- This flag is present in header files, but is an internal feature and should
- not be used. It will be removed in a future version of CPython
+ This flag is present in header files, but is not be used.
+ It will be removed in a future version of CPython
+
+
+ .. c:macro:: Py_TPFLAGS_HAVE_VERSION_TAG
+
+ This is a :term:`soft deprecated` macro that does nothing.
+ Historically, this would indicate that the
+ :c:member:`~PyTypeObject.tp_version_tag` field was available and
+ initialized.
+
+
+ .. c:macro:: Py_TPFLAGS_INLINE_VALUES
+
+ This bit indicates that instances of this type will have an "inline values"
+ array (containing the object's attributes) placed directly after the end
+ of the object.
+
+ This requires that :c:macro:`Py_TPFLAGS_HAVE_GC` is set.
+
+ **Inheritance:**
+
+ This flag is not inherited.
+
+ .. versionadded:: 3.13
+
+
+ .. c:macro:: Py_TPFLAGS_IS_ABSTRACT
+
+ This bit indicates that this is an abstract type and therefore cannot
+ be instantiated.
+
+ **Inheritance:**
+
+ This flag is not inherited.
+
+ .. seealso::
+ :mod:`abc`
+
+
+ .. c:macro:: Py_TPFLAGS_HAVE_STACKLESS_EXTENSION
+
+ Internal. Do not set or unset this flag.
+ Historically, this was a reserved flag for use in Stackless Python.
+
+ .. warning::
+ This flag is present in header files, but is not be used.
+ This may be removed in a future version of CPython.
.. c:member:: const char* PyTypeObject.tp_doc
+ .. corresponding-type-slot:: Py_tp_doc
+
An optional pointer to a NUL-terminated C string giving the docstring for this
- type object. This is exposed as the :attr:`__doc__` attribute on the type and
- instances of the type.
+ type object. This is exposed as the :attr:`~type.__doc__` attribute on the
+ type and instances of the type.
**Inheritance:**
@@ -1345,6 +1473,8 @@ 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::
@@ -1405,6 +1535,11 @@ 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.
@@ -1435,6 +1570,8 @@ 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 for the garbage collector. This is only
used if the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit is set. The signature is::
@@ -1477,7 +1614,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
:c:func:`Py_CLEAR` macro performs the operations in a safe order.
If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the
- :c:member:`~PyTypeObject.tp_flags` field, the traverse function must call
+ :c:member:`~PyTypeObject.tp_flags` field, the clear function must call
:c:func:`PyObject_ClearManagedDict` like this::
PyObject_ClearManagedDict((PyObject*)self);
@@ -1509,6 +1646,8 @@ 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);
@@ -1592,7 +1731,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
weak references to the type object itself.
It is an error to set both the :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` bit and
- :c:member:`~PyTypeObject.tp_weaklist`.
+ :c:member:`~PyTypeObject.tp_weaklistoffset`.
**Inheritance:**
@@ -1604,13 +1743,15 @@ and :c:data:`PyType_Type` effectively act as defaults.)
**Default:**
If the :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` bit is set in the
- :c:member:`~PyTypeObject.tp_dict` field, then
+ :c:member:`~PyTypeObject.tp_flags` field, then
:c:member:`~PyTypeObject.tp_weaklistoffset` will be set to a negative value,
to indicate that it is unsafe to use this field.
.. 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).
@@ -1626,6 +1767,8 @@ 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::
@@ -1649,6 +1792,8 @@ 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.
@@ -1663,6 +1808,8 @@ 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.
@@ -1678,6 +1825,8 @@ 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.
@@ -1692,6 +1841,8 @@ 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.
@@ -1764,6 +1915,8 @@ 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::
@@ -1779,6 +1932,8 @@ 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.
@@ -1816,7 +1971,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
dictionary, so it is may be more efficient to call :c:func:`PyObject_GetAttr`
when accessing an attribute on the object.
- It is an error to set both the :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` bit and
+ It is an error to set both the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit and
:c:member:`~PyTypeObject.tp_dictoffset`.
**Inheritance:**
@@ -1839,6 +1994,8 @@ 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
@@ -1874,6 +2031,8 @@ 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::
@@ -1898,6 +2057,8 @@ 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::
@@ -1937,6 +2098,8 @@ 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);
@@ -1959,6 +2122,8 @@ 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
@@ -1987,6 +2152,8 @@ 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.
@@ -2036,7 +2203,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
A collection of subclasses. Internal use only. May be an invalid pointer.
To get a list of subclasses, call the Python method
- :py:meth:`~class.__subclasses__`.
+ :py:meth:`~type.__subclasses__`.
.. versionchanged:: 3.12
@@ -2067,6 +2234,8 @@ 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.
@@ -2081,7 +2250,11 @@ and :c:data:`PyType_Type` effectively act as defaults.)
.. c:member:: destructor PyTypeObject.tp_finalize
- An optional pointer to an instance finalization function. Its signature is::
+ .. 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::
void tp_finalize(PyObject *self);
@@ -2098,28 +2271,15 @@ and :c:data:`PyType_Type` effectively act as defaults.)
static void
local_finalize(PyObject *self)
{
- PyObject *error_type, *error_value, *error_traceback;
-
/* Save the current exception, if any. */
- PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ PyObject *exc = PyErr_GetRaisedException();
/* ... */
/* Restore the saved exception. */
- PyErr_Restore(error_type, error_value, error_traceback);
+ PyErr_SetRaisedException(exc);
}
- Also, note that, in a garbage collected Python,
- :c:member:`~PyTypeObject.tp_dealloc` may be called from
- any Python thread, not just the thread which created the object (if the object
- becomes part of a refcount cycle, that cycle might be collected by a garbage
- collection on any thread). This is not a problem for Python API calls, since
- the thread on which tp_dealloc is called will own the Global Interpreter Lock
- (GIL). However, if the object being destroyed in turn destroys objects from some
- other C or C++ library, care should be taken to ensure that destroying those
- objects on the thread which called tp_dealloc will not violate any assumptions
- of the library.
-
**Inheritance:**
This field is inherited by subtypes.
@@ -2199,7 +2359,7 @@ This is done by filling a :c:type:`PyType_Spec` structure and calling
.. _number-structs:
Number Object Structures
-========================
+------------------------
.. sectionauthor:: Amaury Forgeot d'Arc
@@ -2273,47 +2433,153 @@ 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:
Mapping Object Structures
-=========================
+-------------------------
.. sectionauthor:: Amaury Forgeot d'Arc
@@ -2325,12 +2591,16 @@ 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
@@ -2339,6 +2609,8 @@ 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
@@ -2350,7 +2622,7 @@ Mapping Object Structures
.. _sequence-structs:
Sequence Object Structures
-==========================
+--------------------------
.. sectionauthor:: Amaury Forgeot d'Arc
@@ -2362,6 +2634,8 @@ 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`
@@ -2369,18 +2643,24 @@ 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.
@@ -2394,6 +2674,8 @@ 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
@@ -2403,6 +2685,8 @@ 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
@@ -2410,6 +2694,8 @@ 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`
@@ -2419,6 +2705,8 @@ 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`
@@ -2430,7 +2718,7 @@ Sequence Object Structures
.. _buffer-structs:
Buffer Object Structures
-========================
+------------------------
.. sectionauthor:: Greg J. Stein
.. sectionauthor:: Benjamin Peterson
@@ -2444,6 +2732,8 @@ 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);
@@ -2453,13 +2743,13 @@ Buffer Object Structures
steps:
(1) Check if the request can be met. If not, raise :exc:`BufferError`,
- set :c:expr:`view->obj` to ``NULL`` and return ``-1``.
+ set ``view->obj`` to ``NULL`` and return ``-1``.
(2) Fill in the requested fields.
(3) Increment an internal counter for the number of exports.
- (4) Set :c:expr:`view->obj` to *exporter* and increment :c:expr:`view->obj`.
+ (4) Set ``view->obj`` to *exporter* and increment ``view->obj``.
(5) Return ``0``.
@@ -2467,10 +2757,10 @@ Buffer Object Structures
schemes can be used:
* Re-export: Each member of the tree acts as the exporting object and
- sets :c:expr:`view->obj` to a new reference to itself.
+ sets ``view->obj`` to a new reference to itself.
* Redirect: The buffer request is redirected to the root object of the
- tree. Here, :c:expr:`view->obj` will be a new reference to the root
+ tree. Here, ``view->obj`` will be a new reference to the root
object.
The individual fields of *view* are described in section
@@ -2493,6 +2783,8 @@ 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);
@@ -2512,7 +2804,7 @@ Buffer Object Structures
*view* argument.
- This function MUST NOT decrement :c:expr:`view->obj`, since that is
+ This function MUST NOT decrement ``view->obj``, since that is
done automatically in :c:func:`PyBuffer_Release` (this scheme is
useful for breaking reference cycles).
@@ -2525,7 +2817,7 @@ Buffer Object Structures
Async Object Structures
-=======================
+-----------------------
.. sectionauthor:: Yury Selivanov
@@ -2547,6 +2839,8 @@ 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);
@@ -2558,6 +2852,8 @@ 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);
@@ -2570,6 +2866,8 @@ 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);
@@ -2580,6 +2878,8 @@ 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);
@@ -2593,7 +2893,7 @@ Async Object Structures
.. _slot-typedefs:
Slot Type typedefs
-==================
+------------------
.. c:type:: PyObject *(*allocfunc)(PyTypeObject *cls, Py_ssize_t nitems)
@@ -2616,7 +2916,7 @@ Slot Type typedefs
See :c:member:`~PyTypeObject.tp_free`.
-.. c:type:: PyObject *(*newfunc)(PyObject *, PyObject *, PyObject *)
+.. c:type:: PyObject *(*newfunc)(PyTypeObject *, PyObject *, PyObject *)
See :c:member:`~PyTypeObject.tp_new`.
@@ -2702,7 +3002,7 @@ Slot Type typedefs
.. _typedef-examples:
Examples
-========
+--------
The following are simple examples of Python type definitions. They
include common usage you may encounter. Some demonstrate tricky corner
diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst
index 7320d035bab513e..feca7a92e271658 100644
--- a/Doc/c-api/unicode.rst
+++ b/Doc/c-api/unicode.rst
@@ -68,8 +68,14 @@ Python:
.. c:var:: PyTypeObject PyUnicode_Type
- This instance of :c:type:`PyTypeObject` represents the Python Unicode type. It
- is exposed to Python code as ``str``.
+ This instance of :c:type:`PyTypeObject` represents the Python Unicode type.
+ It is exposed to Python code as ``str``.
+
+
+.. c:var:: PyTypeObject PyUnicodeIter_Type
+
+ This instance of :c:type:`PyTypeObject` represents the Python Unicode
+ iterator type. It is used to iterate over Unicode string objects.
The following APIs are C macros and static inlined functions for fast checks and
@@ -256,13 +262,8 @@ the Python configuration.
.. c:function:: int Py_UNICODE_ISPRINTABLE(Py_UCS4 ch)
- Return ``1`` or ``0`` depending on whether *ch* is a printable character.
- Nonprintable characters are those characters defined in the Unicode character
- database as "Other" or "Separator", excepting the ASCII space (0x20) which is
- considered printable. (Note that printable characters in this context are
- those which should not be escaped when :func:`repr` is invoked on a string.
- It has no bearing on the handling of strings written to :data:`sys.stdout` or
- :data:`sys.stderr`.)
+ Return ``1`` or ``0`` depending on whether *ch* is a printable character,
+ in the sense of :meth:`str.isprintable`.
These APIs can be used for fast direct character conversions:
@@ -315,12 +316,22 @@ 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 characters and return a single :c:type:`Py_UCS4` value.
+ 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
@@ -338,6 +349,8 @@ APIs:
This is the recommended way to allocate a new Unicode object. Objects
created using this function are not resizable.
+ On error, set an exception and return ``NULL``.
+
.. versionadded:: 3.3
@@ -592,6 +605,14 @@ APIs:
Objects other than Unicode or its subtypes will cause a :exc:`TypeError`.
+.. c:function:: PyObject* PyUnicode_FromOrdinal(int ordinal)
+
+ Create a Unicode Object from the given Unicode code point *ordinal*.
+
+ The ordinal must be in ``range(0x110000)``. A :exc:`ValueError` is
+ raised in the case it is not.
+
+
.. c:function:: PyObject* PyUnicode_FromEncodedObject(PyObject *obj, \
const char *encoding, const char *errors)
@@ -610,10 +631,31 @@ APIs:
decref'ing the returned objects.
+.. c:function:: PyObject* PyUnicode_BuildEncodingMap(PyObject* string)
+
+ Return a mapping suitable for decoding a custom single-byte encoding.
+ Given a Unicode string *string* of up to 256 characters representing an encoding
+ table, returns either a compact internal mapping object or a dictionary
+ mapping character ordinals to byte values. Raises a :exc:`TypeError` and
+ return ``NULL`` on invalid input.
+ .. versionadded:: 3.2
+
+
+.. c:function:: const char* PyUnicode_GetDefaultEncoding(void)
+
+ Return the name of the default string encoding, ``"utf-8"``.
+ See :func:`sys.getdefaultencoding`.
+
+ The returned string does not need to be freed, and is valid
+ until interpreter shutdown.
+
+
.. c:function:: Py_ssize_t PyUnicode_GetLength(PyObject *unicode)
Return the length of the Unicode object, in code points.
+ On error, set an exception and return ``-1``.
+
.. versionadded:: 3.3
@@ -640,7 +682,7 @@ APIs:
Fail if *fill_char* is bigger than the string maximum character, or if the
string has more than 1 reference.
- Return the number of written character, or return ``-1`` and raise an
+ Return the number of written characters, or return ``-1`` and raise an
exception on error.
.. versionadded:: 3.3
@@ -657,6 +699,8 @@ APIs:
not out of bounds, and that the object can be modified safely (i.e. that it
its reference count is one).
+ Return ``0`` on success, ``-1`` on error with an exception set.
+
.. versionadded:: 3.3
@@ -666,6 +710,8 @@ APIs:
Unicode object and the index is not out of bounds, in contrast to
:c:func:`PyUnicode_READ_CHAR`, which performs no error checking.
+ Return character on success, ``-1`` on error with an exception set.
+
.. versionadded:: 3.3
@@ -674,6 +720,7 @@ APIs:
Return a substring of *unicode*, from character index *start* (included) to
character index *end* (excluded). Negative indices are not supported.
+ On error, set an exception and return ``NULL``.
.. versionadded:: 3.3
@@ -777,16 +824,25 @@ Functions encoding to and decoding from the :term:`filesystem encoding and
error handler` (:pep:`383` and :pep:`529`).
To encode file names to :class:`bytes` during argument parsing, the ``"O&"``
-converter should be used, passing :c:func:`PyUnicode_FSConverter` as the
+converter should be used, passing :c:func:`!PyUnicode_FSConverter` as the
conversion function:
.. c:function:: int PyUnicode_FSConverter(PyObject* obj, void* result)
- ParseTuple converter: encode :class:`str` objects -- obtained directly or
+ :ref:`PyArg_Parse\* converter `: encode :class:`str` objects -- obtained directly or
through the :class:`os.PathLike` interface -- to :class:`bytes` using
:c:func:`PyUnicode_EncodeFSDefault`; :class:`bytes` objects are output as-is.
- *result* must be a :c:expr:`PyBytesObject*` which must be released when it is
- no longer used.
+ *result* must be an address of a C variable of type :c:expr:`PyObject*`
+ (or :c:expr:`PyBytesObject*`).
+ On success, set the variable to a new :term:`strong reference` to
+ a :ref:`bytes object ` which must be released
+ when it is no longer used and return a non-zero value
+ (:c:macro:`Py_CLEANUP_SUPPORTED`).
+ Embedded null bytes are not allowed in the result.
+ On failure, return ``0`` with an exception set.
+
+ If *obj* is ``NULL``, the function releases a strong reference
+ stored in the variable referred by *result* and returns ``1``.
.. versionadded:: 3.1
@@ -794,16 +850,26 @@ conversion function:
Accepts a :term:`path-like object`.
To decode file names to :class:`str` during argument parsing, the ``"O&"``
-converter should be used, passing :c:func:`PyUnicode_FSDecoder` as the
+converter should be used, passing :c:func:`!PyUnicode_FSDecoder` as the
conversion function:
.. c:function:: int PyUnicode_FSDecoder(PyObject* obj, void* result)
- ParseTuple converter: decode :class:`bytes` objects -- obtained either
+ :ref:`PyArg_Parse\* converter `: decode :class:`bytes` objects -- obtained either
directly or indirectly through the :class:`os.PathLike` interface -- to
:class:`str` using :c:func:`PyUnicode_DecodeFSDefaultAndSize`; :class:`str`
- objects are output as-is. *result* must be a :c:expr:`PyUnicodeObject*` which
- must be released when it is no longer used.
+ objects are output as-is.
+ *result* must be an address of a C variable of type :c:expr:`PyObject*`
+ (or :c:expr:`PyUnicodeObject*`).
+ On success, set the variable to a new :term:`strong reference` to
+ a :ref:`Unicode object ` which must be released
+ when it is no longer used and return a non-zero value
+ (:c:macro:`Py_CLEANUP_SUPPORTED`).
+ Embedded null characters are not allowed in the result.
+ On failure, return ``0`` with an exception set.
+
+ If *obj* is ``NULL``, release the strong reference
+ to the object referred to by *result* and return ``1``.
.. versionadded:: 3.2
@@ -990,6 +1056,9 @@ These are the UTF-8 codec APIs:
object. Error handling is "strict". Return ``NULL`` if an exception was
raised by the codec.
+ The function fails if the string contains surrogate code points
+ (``U+D800`` - ``U+DFFF``).
+
.. c:function:: const char* PyUnicode_AsUTF8AndSize(PyObject *unicode, Py_ssize_t *size)
@@ -1002,6 +1071,9 @@ These are the UTF-8 codec APIs:
On error, set an exception, set *size* to ``-1`` (if it's not NULL) and
return ``NULL``.
+ The function fails if the string contains surrogate code points
+ (``U+D800`` - ``U+DFFF``).
+
This caches the UTF-8 representation of the string in the Unicode object, and
subsequent calls will return a pointer to the same buffer. The caller is not
responsible for deallocating the buffer. The buffer is deallocated and
@@ -1010,7 +1082,7 @@ These are the UTF-8 codec APIs:
.. versionadded:: 3.3
.. versionchanged:: 3.7
- The return type is now ``const char *`` rather of ``char *``.
+ The return type is now ``const char *`` rather than ``char *``.
.. versionchanged:: 3.10
This function is a part of the :ref:`limited API `.
@@ -1020,10 +1092,19 @@ These are the UTF-8 codec APIs:
As :c:func:`PyUnicode_AsUTF8AndSize`, but does not store the size.
+ .. warning::
+
+ This function does not have any special behavior for
+ `null characters `_ embedded within
+ *unicode*. As a result, strings containing null characters will remain in the returned
+ string, which some C functions might interpret as the end of the string, leading to
+ truncation. If truncation is an issue, it is recommended to use :c:func:`PyUnicode_AsUTF8AndSize`
+ instead.
+
.. versionadded:: 3.3
.. versionchanged:: 3.7
- The return type is now ``const char *`` rather of ``char *``.
+ The return type is now ``const char *`` rather than ``char *``.
UTF-32 Codecs
@@ -1309,6 +1390,13 @@ the user settings on the machine running the codec.
in *consumed*.
+.. c:function:: PyObject* PyUnicode_DecodeCodePageStateful(int code_page, const char *str, \
+ Py_ssize_t size, const char *errors, Py_ssize_t *consumed)
+
+ Similar to :c:func:`PyUnicode_DecodeMBCSStateful`, except uses the code page
+ specified by *code_page*.
+
+
.. c:function:: PyObject* PyUnicode_AsMBCSString(PyObject *unicode)
Encode a Unicode object using MBCS and return the result as Python bytes
@@ -1325,10 +1413,6 @@ the user settings on the machine running the codec.
.. versionadded:: 3.3
-Methods & Slots
-"""""""""""""""
-
-
.. _unicodemethodsandslots:
Methods and Slot Functions
@@ -1353,6 +1437,20 @@ They all return ``NULL`` or ``-1`` if an exception occurs.
separator. At most *maxsplit* splits will be done. If negative, no limit is
set. Separators are not included in the resulting list.
+ On error, return ``NULL`` with an exception set.
+
+ Equivalent to :py:meth:`str.split`.
+
+
+.. c:function:: PyObject* PyUnicode_RSplit(PyObject *unicode, PyObject *sep, Py_ssize_t maxsplit)
+
+ Similar to :c:func:`PyUnicode_Split`, but splitting will be done beginning
+ at the end of the string.
+
+ On error, return ``NULL`` with an exception set.
+
+ Equivalent to :py:meth:`str.rsplit`.
+
.. c:function:: PyObject* PyUnicode_Splitlines(PyObject *unicode, int keepends)
@@ -1361,6 +1459,33 @@ They all return ``NULL`` or ``-1`` if an exception occurs.
characters are not included in the resulting strings.
+.. c:function:: PyObject* PyUnicode_Partition(PyObject *unicode, PyObject *sep)
+
+ Split a Unicode string at the first occurrence of *sep*, and return
+ a 3-tuple containing the part before the separator, the separator itself,
+ and the part after the separator. If the separator is not found,
+ return a 3-tuple containing the string itself, followed by two empty strings.
+
+ *sep* must not be empty.
+
+ On error, return ``NULL`` with an exception set.
+
+ Equivalent to :py:meth:`str.partition`.
+
+
+.. c:function:: PyObject* PyUnicode_RPartition(PyObject *unicode, PyObject *sep)
+
+ Similar to :c:func:`PyUnicode_Partition`, but split a Unicode string at the
+ last occurrence of *sep*. If the separator is not found, return a 3-tuple
+ containing two empty strings, followed by the string itself.
+
+ *sep* must not be empty.
+
+ On error, return ``NULL`` with an exception set.
+
+ Equivalent to :py:meth:`str.rpartition`.
+
+
.. c:function:: PyObject* PyUnicode_Join(PyObject *separator, PyObject *seq)
Join a sequence of strings using the given *separator* and return the resulting
@@ -1429,8 +1554,9 @@ They all return ``NULL`` or ``-1`` if an exception occurs.
Compare a Unicode object with a char buffer which is interpreted as
being UTF-8 or ASCII encoded and return true (``1``) if they are equal,
or false (``0``) otherwise.
- If the Unicode object contains surrogate characters or
- the C string is not valid UTF-8, false (``0``) is returned.
+ If the Unicode object contains surrogate code points
+ (``U+D800`` - ``U+DFFF``) or the C string is not valid UTF-8,
+ false (``0``) is returned.
This function does not raise exceptions.
@@ -1490,15 +1616,37 @@ They all return ``NULL`` or ``-1`` if an exception occurs.
existing interned string that is the same as :c:expr:`*p_unicode`, it sets :c:expr:`*p_unicode` to
it (releasing the reference to the old string object and creating a new
:term:`strong reference` to the interned string object), otherwise it leaves
- :c:expr:`*p_unicode` alone and interns it (creating a new :term:`strong reference`).
+ :c:expr:`*p_unicode` alone and interns it.
+
(Clarification: even though there is a lot of talk about references, think
- of this function as reference-neutral; you own the object after the call
- if and only if you owned it before the call.)
+ of this function as reference-neutral. You must own the object you pass in;
+ after the call you no longer own the passed-in reference, but you newly own
+ the result.)
+
+ This function never raises an exception.
+ On error, it leaves its argument unchanged without interning it.
+
+ Instances of subclasses of :py:class:`str` may not be interned, that is,
+ :c:expr:`PyUnicode_CheckExact(*p_unicode)` must be true. If it is not,
+ then -- as with any other error -- the argument is left unchanged.
+
+ Note that interned strings are not “immortal”.
+ You must keep a reference to the result to benefit from interning.
.. c:function:: PyObject* PyUnicode_InternFromString(const char *str)
A combination of :c:func:`PyUnicode_FromString` and
- :c:func:`PyUnicode_InternInPlace`, returning either a new Unicode string
- object that has been interned, or a new ("owned") reference to an earlier
- interned string object with the same value.
+ :c:func:`PyUnicode_InternInPlace`, meant for statically allocated strings.
+
+ Return a new ("owned") reference to either a new Unicode string object
+ that has been interned, or an earlier interned string object with the
+ same value.
+
+ Python may keep a reference to the result, or make it :term:`immortal`,
+ preventing it from being garbage-collected promptly.
+ For interning an unbounded number of different strings, such as ones coming
+ from user input, prefer calling :c:func:`PyUnicode_FromString` and
+ :c:func:`PyUnicode_InternInPlace` directly.
+
+
diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst
index 67167444d0a6852..bba5c7f8ecf7751 100644
--- a/Doc/c-api/veryhigh.rst
+++ b/Doc/c-api/veryhigh.rst
@@ -13,8 +13,9 @@ 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`, and :c:data:`Py_single_input`. These are described
-following the functions which accept them as parameters.
+: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.
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`
@@ -25,30 +26,6 @@ are only passed to these functions if it is certain that they were created by
the same library that the Python runtime is using.
-.. c:function:: int Py_Main(int argc, wchar_t **argv)
-
- The main program for the standard interpreter. This is made available for
- programs which embed Python. The *argc* and *argv* parameters should be
- prepared exactly as those which are passed to a C program's :c:func:`main`
- function (converted to wchar_t according to the user's locale). It is
- important to note that the argument list may be modified (but the contents of
- the strings pointed to by the argument list are not). The return value will
- be ``0`` if the interpreter exits normally (i.e., without an exception),
- ``1`` if the interpreter exits due to an exception, or ``2`` if the parameter
- list does not represent a valid Python command line.
-
- Note that if an otherwise unhandled :exc:`SystemExit` is raised, this
- function will not return ``1``, but exit the process, as long as
- :c:member:`PyConfig.inspect` is zero.
-
-
-.. c:function:: int Py_BytesMain(int argc, char **argv)
-
- Similar to :c:func:`Py_Main` but *argv* is an array of bytes strings.
-
- .. versionadded:: 3.8
-
-
.. c:function:: int PyRun_AnyFile(FILE *fp, const char *filename)
This is a simplified interface to :c:func:`PyRun_AnyFileExFlags` below, leaving
@@ -123,18 +100,12 @@ 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_InteractiveOne(FILE *fp, const char *filename)
-
- This is a simplified interface to :c:func:`PyRun_InteractiveOneFlags` below,
- leaving *flags* set to ``NULL``.
-
-
-.. c:function:: int PyRun_InteractiveOneFlags(FILE *fp, const char *filename, PyCompilerFlags *flags)
+.. 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* is decoded from the
- :term:`filesystem encoding and error handler`.
+ 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
@@ -143,6 +114,19 @@ the same library that the Python runtime is using.
: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,
+ leaving *flags* set to ``NULL``.
+
+
+.. 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
+ :term:`filesystem encoding and error handler`.
+
+
.. c:function:: int PyRun_InteractiveLoop(FILE *fp, const char *filename)
This is a simplified interface to :c:func:`PyRun_InteractiveLoopFlags` below,
@@ -164,7 +148,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 the :file:`Modules/_tkinter.c` in the
+ event loops, as done in :file:`Modules/_tkinter.c` in the
Python source code.
.. versionchanged:: 3.12
@@ -207,7 +191,7 @@ the same library that the Python runtime is using.
objects *globals* and *locals* with the compiler flags specified by
*flags*. *globals* must be a dictionary; *locals* can be any object
that implements the mapping protocol. The parameter *start* specifies
- the start token that should be used to parse the source code.
+ the start symbol and must be one of the :ref:`available start symbols `.
Returns the result of executing the code as a Python object, or ``NULL`` if an
exception was raised.
@@ -255,9 +239,9 @@ the same library that the Python runtime is using.
.. c:function:: PyObject* Py_CompileStringObject(const char *str, PyObject *filename, int start, PyCompilerFlags *flags, int optimize)
Parse and compile the Python source code in *str*, returning the resulting code
- object. The start token is given by *start*; this can be used to constrain the
- 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
+ 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
+ `. 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.
@@ -320,6 +304,171 @@ the same library that the Python runtime is using.
true on success, false on failure.
+.. c:struct:: PyCompilerFlags
+
+ This is the structure used to hold compiler flags. In cases where code is only
+ being compiled, it is passed as ``int flags``, and in cases where code is being
+ executed, it is passed as ``PyCompilerFlags *flags``. In this case, ``from
+ __future__ import`` can modify *flags*.
+
+ Whenever ``PyCompilerFlags *flags`` is ``NULL``, :c:member:`~PyCompilerFlags.cf_flags` is treated as
+ equal to ``0``, and any modification due to ``from __future__ import`` is
+ discarded.
+
+ .. c:member:: int cf_flags
+
+ Compiler flags.
+
+ .. c:member:: int cf_feature_version
+
+ *cf_feature_version* is the minor Python version. It should be
+ initialized to ``PY_MINOR_VERSION``.
+
+ The field is ignored by default, it is used if and only if
+ ``PyCF_ONLY_AST`` flag is set in :c:member:`~PyCompilerFlags.cf_flags`.
+
+ .. versionchanged:: 3.8
+ Added *cf_feature_version* field.
+
+ The available compiler flags are accessible as macros:
+
+ .. c:namespace:: NULL
+
+ .. c:macro:: PyCF_ALLOW_TOP_LEVEL_AWAIT
+ PyCF_ONLY_AST
+ PyCF_OPTIMIZED_AST
+ PyCF_TYPE_COMMENTS
+
+ See :ref:`compiler flags ` in documentation of the
+ :py:mod:`!ast` Python module, which exports these constants under
+ the same names.
+
+ .. rubric:: Low-level flags
+
+ The following flags and masks serve narrow needs of the standard
+ library and interactive interpreters. Code outside the standard
+ library rarely has a reason to use them. They are considered
+ implementation details and may change at any time.
+
+ .. c:macro:: PyCF_ALLOW_INCOMPLETE_INPUT
+
+ This flag is a private interface between the compiler and the
+ :mod:`codeop` module. Do not use it; its behavior is unsupported
+ and may change without warning.
+
+ With this flag set, when compilation fails because the source text
+ ends where more input is expected, for example in the middle of an
+ indented block or an unterminated string literal, the error raised
+ is the undocumented ``_IncompleteInputError``, a subclass of
+ :exc:`SyntaxError`. The :mod:`codeop` module sets this flag,
+ together with :c:macro:`PyCF_DONT_IMPLY_DEDENT`, to tell input
+ that is incomplete apart from input with a real syntax error, so
+ that interactive interpreters know when to prompt for another
+ line instead of reporting an error.
+
+ .. versionadded:: 3.11
+
+ .. c:macro:: PyCF_DONT_IMPLY_DEDENT
+
+ By default, when compiling with the :c:var:`Py_single_input` start
+ symbol, reaching the end of the source text implicitly closes any
+ open indented blocks. With this flag set, open blocks are only
+ closed if the last line of the source ends with a newline; otherwise,
+ compilation fails with a :exc:`SyntaxError`:
+
+ .. code-block:: c
+
+ PyCompilerFlags flags = {
+ .cf_flags = 0,
+ .cf_feature_version = PY_MINOR_VERSION,
+ };
+ const char *source = "if a:\n pass";
+
+ /* The "if" block is closed implicitly;
+ this returns a code object: */
+ Py_CompileStringFlags(source, "", Py_single_input, &flags);
+
+ /* With the flag, this fails with a SyntaxError,
+ because the last line does not end with a newline: */
+ flags.cf_flags = PyCF_DONT_IMPLY_DEDENT;
+ Py_CompileStringFlags(source, "", Py_single_input, &flags);
+
+ The :mod:`codeop` module uses this flag to detect incomplete
+ interactive input. While the user is still typing inside an
+ indented block, the source does not yet end with a newline, so it
+ fails to compile and the user is prompted for another line.
+
+ .. c:macro:: PyCF_IGNORE_COOKIE
+
+ Read the source text as UTF-8, ignoring its :pep:`263` encoding
+ declaration ("coding cookie"), if any:
+
+ .. code-block:: c
+
+ PyCompilerFlags flags = {
+ .cf_flags = 0,
+ .cf_feature_version = PY_MINOR_VERSION,
+ };
+ const char *source = "# coding: latin-1\ns = '\xe9'\n";
+
+ /* The coding cookie is honored: byte 0xE9 is decoded as
+ Latin-1, and this returns a code object that sets s to "é": */
+ Py_CompileStringFlags(source, "", Py_file_input, &flags);
+
+ /* With the flag, the cookie is ignored and compilation fails
+ with a SyntaxError, because 0xE9 is not valid UTF-8: */
+ flags.cf_flags = PyCF_IGNORE_COOKIE;
+ Py_CompileStringFlags(source, "", Py_file_input, &flags);
+
+ The :func:`compile`, :func:`eval` and :func:`exec` built-in functions
+ set this flag when the source is a :class:`str` object, because they
+ pass the text to the parser encoded as UTF-8.
+
+ .. c:macro:: PyCF_SOURCE_IS_UTF8
+
+ Mark the source text as known to be UTF-8 encoded.
+ The :func:`compile`, :func:`eval` and :func:`exec` built-in functions
+ set this flag, but it currently has no effect.
+
+ The "``PyCF``" flags above can be combined with "``CO_FUTURE``" flags such
+ as :c:macro:`CO_FUTURE_ANNOTATIONS` to enable features normally
+ selectable using :ref:`future statements `.
+ See :ref:`c_codeobject_flags` for a complete list.
+
+ The following masks combine several flags:
+
+ .. c:macro:: PyCF_MASK
+
+ Bitmask of all ``CO_FUTURE`` flags (see :ref:`c_codeobject_flags`),
+ which select features normally enabled by
+ :ref:`future statements `.
+ When code compiled with a ``PyCompilerFlags *flags`` argument
+ contains a ``from __future__ import`` statement, the flag for the
+ imported feature is added to *flags*, so that code executed later
+ in the same context inherits it.
+
+ .. c:macro:: PyCF_MASK_OBSOLETE
+
+ Do not use this mask in new code. It is kept only so that old
+ code passing its flags to :func:`compile` keeps working.
+
+ Bitmask of flags for obsolete future features that no longer
+ have any effect.
+
+ .. c:macro:: PyCF_COMPILE_MASK
+
+ Bitmask of all ``PyCF`` flags that change how the source is
+ compiled, such as :c:macro:`PyCF_ONLY_AST`.
+ The :func:`compile` built-in function uses this mask to validate
+ its *flags* argument.
+
+
+.. _start-symbols:
+
+Available start symbols
+^^^^^^^^^^^^^^^^^^^^^^^
+
+
.. c:var:: int Py_eval_input
.. index:: single: Py_CompileString (C function)
@@ -346,34 +495,58 @@ the same library that the Python runtime is using.
interpreter loop.
-.. c:struct:: PyCompilerFlags
+.. c:var:: int Py_func_type_input
- This is the structure used to hold compiler flags. In cases where code is only
- being compiled, it is passed as ``int flags``, and in cases where code is being
- executed, it is passed as ``PyCompilerFlags *flags``. In this case, ``from
- __future__ import`` can modify *flags*.
+ .. index:: single: Py_CompileString (C function)
- Whenever ``PyCompilerFlags *flags`` is ``NULL``, :c:member:`~PyCompilerFlags.cf_flags` is treated as
- equal to ``0``, and any modification due to ``from __future__ import`` is
- discarded.
+ 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`.
- .. c:member:: int cf_flags
+ This requires the :c:macro:`PyCF_ONLY_AST` flag to be set.
- Compiler flags.
+ .. seealso::
+ * :py:class:`ast.FunctionType`
+ * :pep:`484`
- .. c:member:: int cf_feature_version
+ .. versionadded:: 3.8
- *cf_feature_version* is the minor Python version. It should be
- initialized to ``PY_MINOR_VERSION``.
- The field is ignored by default, it is used if and only if
- ``PyCF_ONLY_AST`` flag is set in :c:member:`~PyCompilerFlags.cf_flags`.
+Stack Effects
+^^^^^^^^^^^^^
- .. versionchanged:: 3.8
- Added *cf_feature_version* field.
+.. seealso::
+ :py:func:`dis.stack_effect`
-.. c:var:: int CO_FUTURE_DIVISION
+.. c:macro:: PY_INVALID_STACK_EFFECT
- This bit can be set in *flags* to cause division operator ``/`` to be
- interpreted as "true division" according to :pep:`238`.
+ 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
diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst
index 038f54a9751fd13..ae19d5feea1a991 100644
--- a/Doc/c-api/weakref.rst
+++ b/Doc/c-api/weakref.rst
@@ -19,7 +19,14 @@ as much as it can.
.. c:function:: int PyWeakref_CheckRef(PyObject *ob)
- Return non-zero if *ob* is a reference object. This function always succeeds.
+ 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.
.. c:function:: int PyWeakref_CheckProxy(PyObject *ob)
@@ -35,8 +42,12 @@ as much as it can.
callable object that receives notification when *ob* is garbage collected; it
should accept a single parameter, which will be the weak reference object
itself. *callback* may also be ``None`` or ``NULL``. If *ob* is not a
- weakly referencable object, or if *callback* is not callable, ``None``, or
- ``NULL``, this will return ``NULL`` and raise :exc:`TypeError`.
+ weakly referenceable object, this will raise :exc:`TypeError` and return
+ ``NULL``.
+
+ .. seealso::
+ :c:func:`PyType_SUPPORTS_WEAKREFS` for checking if *ob* is weakly
+ referenceable.
.. c:function:: PyObject* PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
@@ -47,8 +58,12 @@ as much as it can.
be a callable object that receives notification when *ob* is garbage
collected; it should accept a single parameter, which will be the weak
reference object itself. *callback* may also be ``None`` or ``NULL``. If *ob*
- is not a weakly referencable object, or if *callback* is not callable,
- ``None``, or ``NULL``, this will return ``NULL`` and raise :exc:`TypeError`.
+ weakly referenceable object, this will raise :exc:`TypeError` and return
+ ``NULL``.
+
+ .. seealso::
+ :c:func:`PyType_SUPPORTS_WEAKREFS` for checking if *ob* is weakly
+ referenceable.
.. c:function:: int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
@@ -96,3 +111,19 @@ as much as it can.
This iterates through the weak references for *object* and calls callbacks
for those references which have one. It returns when all callbacks have
been attempted.
+
+
+.. c:function:: void PyUnstable_Object_ClearWeakRefsNoCallbacks(PyObject *object)
+
+ Clears the weakrefs for *object* without calling the callbacks.
+
+ This function is called by the :c:member:`~PyTypeObject.tp_dealloc` handler
+ for types with finalizers (i.e., :meth:`~object.__del__`). The handler for
+ those objects first calls :c:func:`PyObject_ClearWeakRefs` to clear weakrefs
+ and call their callbacks, then the finalizer, and finally this function to
+ clear any weakrefs that may have been created by the finalizer.
+
+ In most circumstances, it's more appropriate to use
+ :c:func:`PyObject_ClearWeakRefs` to clear weakrefs instead of this function.
+
+ .. versionadded:: 3.13
diff --git a/Doc/conf.py b/Doc/conf.py
index 86371d17ae742a3..677f948efa51045 100644
--- a/Doc/conf.py
+++ b/Doc/conf.py
@@ -8,21 +8,29 @@
import os
import sys
-import time
+from importlib.util import find_spec
+
+# Make our custom extensions available to Sphinx
sys.path.append(os.path.abspath('tools/extensions'))
sys.path.append(os.path.abspath('includes'))
-from pyspecific import SOURCE_URI
+from patchlevel import get_header_version_info, get_version_info
# General configuration
# ---------------------
+# Our custom Sphinx extensions are found in Doc/Tools/extensions/
extensions = [
- 'asdl_highlight',
+ 'audit_events',
+ 'availability',
'c_annotations',
- 'escape4chm',
+ 'changes',
'glossary_search',
- 'peg_highlight',
+ 'implementation_detail',
+ 'issue_role',
+ 'lexers',
+ 'misc_news',
+ 'pydoc_topics',
'pyspecific',
'sphinx.ext.coverage',
'sphinx.ext.doctest',
@@ -30,19 +38,20 @@
]
# Skip if downstream redistributors haven't installed them
-try:
- import notfound.extension
-except ImportError:
- pass
-else:
- extensions.append('notfound.extension')
-try:
- import sphinxext.opengraph
-except ImportError:
- pass
-else:
- extensions.append('sphinxext.opengraph')
-
+_OPTIONAL_EXTENSIONS = (
+ 'sphinx_linklint.ext',
+ 'notfound.extension',
+ 'sphinxext.opengraph',
+ 'sphinxext.rediraffe',
+ 'sphinxcontrib.rsvgconverter',
+)
+for optional_ext in _OPTIONAL_EXTENSIONS:
+ try:
+ if find_spec(optional_ext) is not None:
+ extensions.append(optional_ext)
+ except (ImportError, ValueError):
+ pass
+del _OPTIONAL_EXTENSIONS
doctest_global_setup = '''
try:
@@ -50,7 +59,7 @@
except ImportError:
_tkinter = None
# Treat warnings as errors, done here to prevent warnings in Sphinx code from
-# causing spurious test failures.
+# causing spurious CPython test failures.
import warnings
warnings.simplefilter('error')
del warnings
@@ -60,37 +69,45 @@
# General substitutions.
project = 'Python'
-copyright = f"2001-{time.strftime('%Y')}, Python Software Foundation"
+copyright = "2001-%Y, Python Software Foundation"
+_doc_authors = 'Python documentation authors'
# We look for the Include/patchlevel.h file in the current Python source tree
# and replace the values accordingly.
-import patchlevel
-version, release = patchlevel.get_version_info()
+# See Doc/tools/extensions/patchlevel.py
+version, release = get_version_info()
+v = get_header_version_info()
+branch = "main" if v.releaselevel == "alpha" else f"{v.major}.{v.minor}"
rst_epilog = f"""
.. |python_version_literal| replace:: ``Python {version}``
.. |python_x_dot_y_literal| replace:: ``python{version}``
+.. |python_x_dot_y_t_literal| replace:: ``python{version}t``
+.. |python_x_dot_y_t_literal_config| replace:: ``python{version}t-config``
+.. |x_dot_y_b2_literal| replace:: ``{version}.0b2``
+.. |applications_python_version_literal| replace:: ``/Applications/Python {version}/``
.. |usr_local_bin_python_x_dot_y_literal| replace:: ``/usr/local/bin/python{version}``
"""
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
+# There are two options for replacing |today|. Either, you set today to some
+# non-false value and use it.
today = ''
-# Else, today_fmt is used as the format for a strftime call.
+# Or else, today_fmt is used as the format for a strftime call.
today_fmt = '%B %d, %Y'
# By default, highlight as Python 3.
highlight_language = 'python3'
# Minimum version of sphinx required
-needs_sphinx = '4.2'
+# Keep this version in sync with ``Doc/requirements.txt``.
+needs_sphinx = '8.2.0'
# Create table of contents entries for domain objects (e.g. functions, classes,
# attributes, etc.). Default is True.
toc_object_entries = False
# Ignore any .rst files in the includes/ directory;
-# they're embedded in pages but not rendered individually.
+# they're embedded in pages but not rendered as individual pages.
# Ignore any .rst files in the venv/ directory.
exclude_patterns = ['includes/*.rst', 'venv/*', 'README.rst']
venvdir = os.getenv('VENVDIR')
@@ -131,6 +148,8 @@
('c:func', 'vsnprintf'),
# Standard C types
('c:type', 'FILE'),
+ ('c:type', 'int8_t'),
+ ('c:type', 'int16_t'),
('c:type', 'int32_t'),
('c:type', 'int64_t'),
('c:type', 'intmax_t'),
@@ -140,6 +159,9 @@
('c:type', 'size_t'),
('c:type', 'ssize_t'),
('c:type', 'time_t'),
+ ('c:type', 'uint8_t'),
+ ('c:type', 'uint16_t'),
+ ('c:type', 'uint32_t'),
('c:type', 'uint64_t'),
('c:type', 'uintmax_t'),
('c:type', 'uintptr_t'),
@@ -148,6 +170,7 @@
('c:type', '__int64'),
('c:type', 'unsigned __int64'),
('c:type', 'double'),
+ ('c:type', '_Float16'),
# Standard C structures
('c:struct', 'in6_addr'),
('c:struct', 'in_addr'),
@@ -182,6 +205,7 @@
('envvar', 'LC_TIME'),
('envvar', 'LINES'),
('envvar', 'LOGNAME'),
+ ('envvar', 'MANPAGER'),
('envvar', 'PAGER'),
('envvar', 'PATH'),
('envvar', 'PATHEXT'),
@@ -194,84 +218,11 @@
('envvar', 'USER'),
('envvar', 'USERNAME'),
('envvar', 'USERPROFILE'),
- # Deprecated function that was never documented:
- ('py:func', 'getargspec'),
- ('py:func', 'inspect.getargspec'),
- # Undocumented modules that users shouldn't have to worry about
- # (implementation details of `os.path`):
- ('py:mod', 'ntpath'),
- ('py:mod', 'posixpath'),
]
# Temporary undocumented names.
# In future this list must be empty.
nitpick_ignore += [
- # C API: Standard Python exception classes
- ('c:data', 'PyExc_ArithmeticError'),
- ('c:data', 'PyExc_AssertionError'),
- ('c:data', 'PyExc_AttributeError'),
- ('c:data', 'PyExc_BaseException'),
- ('c:data', 'PyExc_BlockingIOError'),
- ('c:data', 'PyExc_BrokenPipeError'),
- ('c:data', 'PyExc_BufferError'),
- ('c:data', 'PyExc_ChildProcessError'),
- ('c:data', 'PyExc_ConnectionAbortedError'),
- ('c:data', 'PyExc_ConnectionError'),
- ('c:data', 'PyExc_ConnectionRefusedError'),
- ('c:data', 'PyExc_ConnectionResetError'),
- ('c:data', 'PyExc_EOFError'),
- ('c:data', 'PyExc_Exception'),
- ('c:data', 'PyExc_FileExistsError'),
- ('c:data', 'PyExc_FileNotFoundError'),
- ('c:data', 'PyExc_FloatingPointError'),
- ('c:data', 'PyExc_GeneratorExit'),
- ('c:data', 'PyExc_ImportError'),
- ('c:data', 'PyExc_IndentationError'),
- ('c:data', 'PyExc_IndexError'),
- ('c:data', 'PyExc_InterruptedError'),
- ('c:data', 'PyExc_IsADirectoryError'),
- ('c:data', 'PyExc_KeyboardInterrupt'),
- ('c:data', 'PyExc_KeyError'),
- ('c:data', 'PyExc_LookupError'),
- ('c:data', 'PyExc_MemoryError'),
- ('c:data', 'PyExc_ModuleNotFoundError'),
- ('c:data', 'PyExc_NameError'),
- ('c:data', 'PyExc_NotADirectoryError'),
- ('c:data', 'PyExc_NotImplementedError'),
- ('c:data', 'PyExc_OSError'),
- ('c:data', 'PyExc_OverflowError'),
- ('c:data', 'PyExc_PermissionError'),
- ('c:data', 'PyExc_ProcessLookupError'),
- ('c:data', 'PyExc_RecursionError'),
- ('c:data', 'PyExc_ReferenceError'),
- ('c:data', 'PyExc_RuntimeError'),
- ('c:data', 'PyExc_StopAsyncIteration'),
- ('c:data', 'PyExc_StopIteration'),
- ('c:data', 'PyExc_SyntaxError'),
- ('c:data', 'PyExc_SystemError'),
- ('c:data', 'PyExc_SystemExit'),
- ('c:data', 'PyExc_TabError'),
- ('c:data', 'PyExc_TimeoutError'),
- ('c:data', 'PyExc_TypeError'),
- ('c:data', 'PyExc_UnboundLocalError'),
- ('c:data', 'PyExc_UnicodeDecodeError'),
- ('c:data', 'PyExc_UnicodeEncodeError'),
- ('c:data', 'PyExc_UnicodeError'),
- ('c:data', 'PyExc_UnicodeTranslateError'),
- ('c:data', 'PyExc_ValueError'),
- ('c:data', 'PyExc_ZeroDivisionError'),
- # C API: Standard Python warning classes
- ('c:data', 'PyExc_BytesWarning'),
- ('c:data', 'PyExc_DeprecationWarning'),
- ('c:data', 'PyExc_FutureWarning'),
- ('c:data', 'PyExc_ImportWarning'),
- ('c:data', 'PyExc_PendingDeprecationWarning'),
- ('c:data', 'PyExc_ResourceWarning'),
- ('c:data', 'PyExc_RuntimeWarning'),
- ('c:data', 'PyExc_SyntaxWarning'),
- ('c:data', 'PyExc_UnicodeWarning'),
- ('c:data', 'PyExc_UserWarning'),
- ('c:data', 'PyExc_Warning'),
# 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.
@@ -279,10 +230,7 @@
# Attributes/methods/etc. that definitely should be documented better,
# but are deferred for now:
('py:attr', '__annotations__'),
- ('py:meth', '__missing__'),
('py:attr', '__wrapped__'),
- ('py:attr', 'decimal.Context.clamp'),
- ('py:meth', 'index'), # list.index, tuple.index, etc.
]
# gh-106948: Copy standard C types declared in the "c:type" domain and C
@@ -296,7 +244,8 @@
# Disable Docutils smartquotes for several translations
smartquotes_excludes = {
- 'languages': ['ja', 'fr', 'zh_TW', 'zh_CN'], 'builders': ['man', 'text'],
+ 'languages': ['ja', 'fr', 'zh_TW', 'zh_CN'],
+ 'builders': ['man', 'text'],
}
# Avoid a warning with Sphinx >= 4.0
@@ -305,23 +254,27 @@
# Allow translation of index directives
gettext_additional_targets = [
'index',
+ 'literal-block',
]
# Options for HTML output
# -----------------------
-# Use our custom theme.
+# Use our custom theme: https://github.com/python/python-docs-theme
html_theme = 'python_docs_theme'
+# Location of overrides for theme templates and static files
html_theme_path = ['tools']
html_theme_options = {
'collapsiblesidebar': True,
'issues_url': '/bugs.html',
'license_url': '/license.html',
- 'root_include_title': False # We use the version switcher instead.
+ 'root_include_title': False, # We use the version switcher instead.
}
if os.getenv("READTHEDOCS"):
- html_theme_options["hosted_on"] = 'Read the Docs'
+ html_theme_options["hosted_on"] = (
+ 'Read the Docs'
+ )
# Override stylesheet fingerprinting for Windows CHM htmlhelp to fix GH-91207
# https://github.com/python/cpython/issues/91207
@@ -335,19 +288,27 @@
# Deployment preview information
# (See .readthedocs.yml and https://docs.readthedocs.io/en/stable/reference/environment-variables.html)
-repository_url = os.getenv("READTHEDOCS_GIT_CLONE_URL")
+is_deployment_preview = os.getenv("READTHEDOCS_VERSION_TYPE") == "external"
+repository_url = os.getenv("READTHEDOCS_GIT_CLONE_URL", "")
+repository_url = repository_url.removesuffix(".git")
html_context = {
- "is_deployment_preview": os.getenv("READTHEDOCS_VERSION_TYPE") == "external",
- "repository_url": repository_url.removesuffix(".git") if repository_url else None,
- "pr_id": os.getenv("READTHEDOCS_VERSION")
+ "is_deployment_preview": is_deployment_preview,
+ "repository_url": repository_url or None,
+ "pr_id": os.getenv("READTHEDOCS_VERSION"),
+ "enable_analytics": os.getenv("PYTHON_DOCS_ENABLE_ANALYTICS"),
+ "source_branch": branch,
}
# This 'Last updated on:' timestamp is inserted at the bottom of every page.
-html_last_updated_fmt = time.strftime('%b %d, %Y (%H:%M UTC)', time.gmtime())
+html_last_updated_fmt = '%b %d, %Y (%H:%M UTC)'
+html_last_updated_use_utc = True
-# Path to find HTML templates.
+# Path to find HTML templates to override theme
templates_path = ['tools/templates']
+# We link to sources on GitHub, so don't copy them into the HTML output.
+html_copy_source = False
+
# Custom sidebar templates, filenames relative to this file.
html_sidebars = {
# Defaults taken from https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-html_sidebars
@@ -374,6 +335,8 @@
# Split the index
html_split_index = True
+# Split pot files one per reST file
+gettext_compact = False
# Options for LaTeX output
# ------------------------
@@ -391,40 +354,99 @@
\let\endVerbatim=\endOriginalVerbatim
\setcounter{tocdepth}{2}
''',
- # The paper size ('letter' or 'a4').
- 'papersize': 'a4',
+ # The paper size ('letterpaper' or 'a4paper').
+ '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 = 'Guido van Rossum and the Python development team'
latex_documents = [
- ('c-api/index', 'c-api.tex',
- 'The Python/C API', _stdauthor, 'manual'),
- ('extending/index', 'extending.tex',
- 'Extending and Embedding Python', _stdauthor, 'manual'),
- ('installing/index', 'installing.tex',
- 'Installing Python Modules', _stdauthor, 'manual'),
- ('library/index', 'library.tex',
- 'The Python Library Reference', _stdauthor, 'manual'),
- ('reference/index', 'reference.tex',
- 'The Python Language Reference', _stdauthor, 'manual'),
- ('tutorial/index', 'tutorial.tex',
- 'Python Tutorial', _stdauthor, 'manual'),
- ('using/index', 'using.tex',
- 'Python Setup and Usage', _stdauthor, 'manual'),
- ('faq/index', 'faq.tex',
- 'Python Frequently Asked Questions', _stdauthor, 'manual'),
- ('whatsnew/' + version, 'whatsnew.tex',
- 'What\'s New in Python', 'A. M. Kuchling', 'howto'),
+ (
+ 'c-api/index',
+ 'c-api.tex',
+ 'The Python/C API',
+ _doc_authors,
+ 'manual',
+ ),
+ (
+ 'extending/index',
+ 'extending.tex',
+ 'Extending and Embedding Python',
+ _doc_authors,
+ 'manual',
+ ),
+ (
+ 'installing/index',
+ 'installing.tex',
+ 'Installing Python Modules',
+ _doc_authors,
+ 'manual',
+ ),
+ (
+ 'builtins/index',
+ 'builtins.tex',
+ 'Python Built-ins Reference',
+ _doc_authors,
+ 'manual',
+ ),
+ (
+ 'library/index',
+ 'library.tex',
+ 'The Python Library Reference',
+ _doc_authors,
+ 'manual',
+ ),
+ (
+ 'reference/index',
+ 'reference.tex',
+ 'The Python Language Reference',
+ _doc_authors,
+ 'manual',
+ ),
+ (
+ 'tutorial/index',
+ 'tutorial.tex',
+ 'Python Tutorial',
+ _doc_authors,
+ 'manual',
+ ),
+ (
+ 'using/index',
+ 'using.tex',
+ 'Python Setup and Usage',
+ _doc_authors,
+ 'manual',
+ ),
+ (
+ 'faq/index',
+ 'faq.tex',
+ 'Python Frequently Asked Questions',
+ _doc_authors,
+ 'manual',
+ ),
+ (
+ 'whatsnew/' + version,
+ 'whatsnew.tex',
+ 'What\'s New in Python',
+ _doc_authors,
+ 'howto',
+ ),
]
# Collect all HOWTOs individually
-latex_documents.extend(('howto/' + fn[:-4], 'howto-' + fn[:-4] + '.tex',
- '', _stdauthor, 'howto')
- for fn in os.listdir('howto')
- if fn.endswith('.rst') and fn != 'index.rst')
+latex_documents.extend(
+ (
+ 'howto/' + fn[:-4],
+ 'howto-' + fn[:-4] + '.tex',
+ '',
+ _doc_authors,
+ 'howto',
+ )
+ for fn in os.listdir('howto')
+ if fn.endswith('.rst') and fn != 'index.rst'
+)
# Documents to append as an appendix to all manuals.
latex_appendices = ['glossary', 'about', 'license', 'copyright']
@@ -432,8 +454,32 @@
# Options for Epub output
# -----------------------
-epub_author = 'Python Documentation Authors'
+epub_author = _doc_authors
epub_publisher = 'Python Software Foundation'
+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
# --------------------------------
@@ -448,8 +494,7 @@
'test($|_)',
]
-coverage_ignore_classes = [
-]
+coverage_ignore_classes = []
# Glob patterns for C source files for C API coverage, relative to this directory.
coverage_c_path = [
@@ -466,7 +511,7 @@
# The coverage checker will ignore all C items whose names match these regexes
# (using re.match) -- the keys must be the same as in coverage_c_regexes.
coverage_ignore_c_items = {
-# 'cfunction': [...]
+ # 'cfunction': [...]
}
@@ -482,15 +527,19 @@
r'https://github.com/python/cpython/tree/.*': 'https://github.com/python/cpython/blob/.*',
# Intentional HTTP use at Misc/NEWS.d/3.5.0a1.rst
r'http://www.python.org/$': 'https://www.python.org/$',
- # Used in license page, keep as is
- r'https://www.zope.org/': r'https://www.zope.dev/',
# Microsoft's redirects to learn.microsoft.com
r'https://msdn.microsoft.com/.*': 'https://learn.microsoft.com/.*',
r'https://docs.microsoft.com/.*': 'https://learn.microsoft.com/.*',
r'https://go.microsoft.com/fwlink/\?LinkID=\d+': 'https://learn.microsoft.com/.*',
+ # Debian's man page redirects to its current stable version
+ r'https://manpages.debian.org/\w+\(\d(\w+)?\)': r'https://manpages.debian.org/\w+/[\w/\-\.]*\.\d(\w+)?\.en\.html',
# Language redirects
r'https://toml.io': 'https://toml.io/en/',
r'https://www.redhat.com': 'https://www.redhat.com/en',
+ # pypi.org project name normalization (upper to lowercase, underscore to hyphen)
+ r'https://pypi.org/project/[A-Za-z\d_\-\.]+/': r'https://pypi.org/project/[a-z\d\-\.]+/',
+ # Discourse title name expansion (text changes when title is edited)
+ r'https://discuss\.python\.org/t/\d+': r'https://discuss\.python\.org/t/.*/\d+',
# Other redirects
r'https://www.boost.org/libs/.+': r'https://www.boost.org/doc/libs/\d_\d+_\d/.+',
r'https://support.microsoft.com/en-us/help/\d+': 'https://support.microsoft.com/en-us/topic/.+',
@@ -517,6 +566,7 @@
r'https://unix.org/version2/whatsnew/lp64_wp.html',
]
+
# Options for sphinx.ext.extlinks
# -------------------------------
@@ -524,26 +574,55 @@
# mapping unique short aliases to a base URL and a prefix.
# https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html
extlinks = {
- "cve": ("https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-%s", "CVE-%s"),
- "cwe": ("https://cwe.mitre.org/data/definitions/%s.html", "CWE-%s"),
+ "oss-fuzz": ("https://issues.oss-fuzz.com/issues/%s", "#%s"),
"pypi": ("https://pypi.org/project/%s/", "%s"),
- "source": (SOURCE_URI, "%s"),
+ "source": (f"https://github.com/python/cpython/tree/{branch}/%s", "%s"),
}
extlinks_detect_hardcoded_links = True
-# Options for extensions
-# ----------------------
+# Options for c_annotations extension
+# -----------------------------------
# Relative filename of the data files
refcount_file = 'data/refcounts.dat'
stable_abi_file = 'data/stable_abi.dat'
-# sphinxext-opengraph config
-ogp_site_url = 'https://docs.python.org/3/'
+# Options for notfound.extension
+# -------------------------------
+
+if not os.getenv("READTHEDOCS"):
+ if language_code:
+ notfound_urls_prefix = (
+ f'/{language_code.replace("_", "-").lower()}/{version}/'
+ )
+ else:
+ notfound_urls_prefix = f'/{version}/'
+
+# Options for sphinxext-opengraph
+# -------------------------------
+
+ogp_canonical_url = 'https://docs.python.org/3/'
ogp_site_name = 'Python documentation'
-ogp_image = '_static/og-image.png'
-ogp_custom_meta_tags = [
- '',
- '',
- '',
-]
+ogp_social_cards = { # Used when matplotlib is installed
+ 'image': '_static/og-image.png',
+ 'line_color': '#3776ab',
+}
+ogp_custom_meta_tags = ('',)
+if 'create-social-cards' not in tags: # noqa: F821
+ # Define a static preview image when not creating social cards
+ ogp_image = '_static/og-image.png'
+ ogp_custom_meta_tags += (
+ '',
+ '',
+ )
+
+# Options for sphinxext-rediraffe
+# -------------------------------
+
+rediraffe_redirects = {
+ # Splitting builtins from library
+ "library/functions.rst": "builtins/functions.rst",
+ "library/stdtypes.rst": "builtins/stdtypes.rst",
+ "library/constants.rst": "builtins/constants.rst",
+ "library/exceptions.rst": "builtins/exceptions.rst",
+}
diff --git a/Doc/constraints.txt b/Doc/constraints.txt
index 147de1271eb2b7f..29cd4be1d3c8dbe 100644
--- a/Doc/constraints.txt
+++ b/Doc/constraints.txt
@@ -7,18 +7,18 @@
# Direct dependencies of Sphinx
babel<3
colorama<0.5
-imagesize<1.5
-Jinja2<3.2
-packaging<24
-Pygments>=2.16.1,<3
+imagesize<2
+Jinja2<4
+packaging<25
+Pygments<3
requests<3
snowballstemmer<3
-sphinxcontrib-applehelp<1.1
-sphinxcontrib-devhelp<1.1
-sphinxcontrib-htmlhelp<2.1
-sphinxcontrib-jsmath<1.1
-sphinxcontrib-qthelp<1.1
-sphinxcontrib-serializinghtml<1.2
+sphinxcontrib-applehelp<3
+sphinxcontrib-devhelp<3
+sphinxcontrib-htmlhelp<3
+sphinxcontrib-jsmath<2
+sphinxcontrib-qthelp<3
+sphinxcontrib-serializinghtml<3
# Direct dependencies of Jinja2 (Jinja is a dependency of Sphinx, see above)
-MarkupSafe<2.2
+MarkupSafe<3
diff --git a/Doc/contents.rst b/Doc/contents.rst
index 24ceacb0076b5eb..852be4a6d5b6ba7 100644
--- a/Doc/contents.rst
+++ b/Doc/contents.rst
@@ -8,12 +8,14 @@
tutorial/index.rst
using/index.rst
reference/index.rst
+ builtins/index.rst
library/index.rst
extending/index.rst
c-api/index.rst
installing/index.rst
howto/index.rst
faq/index.rst
+ deprecations/index.rst
glossary.rst
about.rst
diff --git a/Doc/data/python3.13.abi b/Doc/data/python3.13.abi
new file mode 100644
index 000000000000000..e0588167eba04e5
--- /dev/null
+++ b/Doc/data/python3.13.abi
@@ -0,0 +1,29436 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat
index 62a96146d605ff7..9e0ce81627f2558 100644
--- a/Doc/data/refcounts.dat
+++ b/Doc/data/refcounts.dat
@@ -180,7 +180,7 @@ PyCapsule_IsValid:const char*:name::
PyCapsule_New:PyObject*::+1:
PyCapsule_New:void*:pointer::
PyCapsule_New:const char *:name::
-PyCapsule_New::void (* destructor)(PyObject* )::
+PyCapsule_New:void (*)(PyObject *):destructor::
PyCapsule_SetContext:int:::
PyCapsule_SetContext:PyObject*:self:0:
@@ -349,11 +349,11 @@ PyComplex_CheckExact:int:::
PyComplex_CheckExact:PyObject*:p:0:
PyComplex_FromCComplex:PyObject*::+1:
-PyComplex_FromCComplex::Py_complex v::
+PyComplex_FromCComplex:Py_complex:v::
PyComplex_FromDoubles:PyObject*::+1:
-PyComplex_FromDoubles::double real::
-PyComplex_FromDoubles::double imag::
+PyComplex_FromDoubles:double:real::
+PyComplex_FromDoubles:double:imag::
PyComplex_ImagAsDouble:double:::
PyComplex_ImagAsDouble:PyObject*:op:0:
@@ -622,7 +622,9 @@ PyErr_GetExcInfo:PyObject**:pvalue:+1:
PyErr_GetExcInfo:PyObject**:ptraceback:+1:
PyErr_GetRaisedException:PyObject*::+1:
-PyErr_SetRaisedException::::
+
+PyErr_SetRaisedException:void:::
+PyErr_SetRaisedException:PyObject *:exc:0:stolen
PyErr_GivenExceptionMatches:int:::
PyErr_GivenExceptionMatches:PyObject*:given:0:
@@ -642,9 +644,9 @@ PyErr_NewExceptionWithDoc:PyObject*:dict:0:
PyErr_NoMemory:PyObject*::null:
PyErr_NormalizeException:void:::
-PyErr_NormalizeException:PyObject**:exc::???
-PyErr_NormalizeException:PyObject**:val::???
-PyErr_NormalizeException:PyObject**:tb::???
+PyErr_NormalizeException:PyObject**:exc:+1:???
+PyErr_NormalizeException:PyObject**:val:+1:???
+PyErr_NormalizeException:PyObject**:tb:+1:???
PyErr_Occurred:PyObject*::0:
@@ -790,6 +792,12 @@ PyEval_GetGlobals:PyObject*::0:
PyEval_GetFrame:PyObject*::0:
+PyEval_GetFrameBuiltins:PyObject*::+1:
+
+PyEval_GetFrameLocals:PyObject*::+1:
+
+PyEval_GetFrameGlobals:PyObject*::+1:
+
PyEval_GetFuncDesc:const char*:::
PyEval_GetFuncDesc:PyObject*:func:0:
@@ -916,6 +924,32 @@ PyFloat_FromString:PyObject*:str:0:
PyFloat_GetInfo:PyObject*::+1:
PyFloat_GetInfo::void::
+PyFrame_GetBack:PyObject*::+1:
+PyFrame_GetBack:PyFrameObject*:frame:0:
+
+PyFrame_GetBuiltins:PyObject*::+1:
+PyFrame_GetBuiltins:PyFrameObject*:frame:0:
+
+PyFrame_GetCode:PyObject*::+1:
+PyFrame_GetCode:PyFrameObject*:frame:0:
+
+PyFrame_GetGenerator:PyObject*::+1:
+PyFrame_GetGenerator:PyFrameObject*:frame:0:
+
+PyFrame_GetGlobals:PyObject*::+1:
+PyFrame_GetGlobals:PyFrameObject*:frame:0:
+
+PyFrame_GetLocals:PyObject*::+1:
+PyFrame_GetLocals:PyFrameObject*:frame:0:
+
+PyFrame_GetVar:PyObject*::+1:
+PyFrame_GetVar:PyFrameObject*:frame:0:
+PyFrame_GetVar:PyObject*:name:0:
+
+PyFrame_GetVarString:PyObject*::+1:
+PyFrame_GetVarString:PyFrameObject*:frame:0:
+PyFrame_GetVarString:const char*:name::
+
PyFrozenSet_Check:int:::
PyFrozenSet_Check:PyObject*:p:0:
@@ -931,21 +965,45 @@ PyFunction_Check:PyObject*:o:0:
PyFunction_GetAnnotations:PyObject*::0:
PyFunction_GetAnnotations:PyObject*:op:0:
+PyFunction_GET_ANNOTATIONS:PyObject*::0:
+PyFunction_GET_ANNOTATIONS:PyObject*:op:0:
+
PyFunction_GetClosure:PyObject*::0:
PyFunction_GetClosure:PyObject*:op:0:
+PyFunction_GET_CLOSURE:PyObject*::0:
+PyFunction_GET_CLOSURE:PyObject*:op:0:
+
PyFunction_GetCode:PyObject*::0:
PyFunction_GetCode:PyObject*:op:0:
+PyFunction_GET_CODE:PyObject*::0:
+PyFunction_GET_CODE:PyObject*:op:0:
+
PyFunction_GetDefaults:PyObject*::0:
PyFunction_GetDefaults:PyObject*:op:0:
+PyFunction_GET_DEFAULTS:PyObject*::0:
+PyFunction_GET_DEFAULTS:PyObject*:op:0:
+
+PyFunction_GetKwDefaults:PyObject*::0:
+PyFunction_GetKwDefaults:PyObject*:op:0:
+
+PyFunction_GET_KW_DEFAULTS:PyObject*::0:
+PyFunction_GET_KW_DEFAULTS:PyObject*:op:0:
+
PyFunction_GetGlobals:PyObject*::0:
PyFunction_GetGlobals:PyObject*:op:0:
+PyFunction_GET_GLOBALS:PyObject*::0:
+PyFunction_GET_GLOBALS:PyObject*:op:0:
+
PyFunction_GetModule:PyObject*::0:
PyFunction_GetModule:PyObject*:op:0:
+PyFunction_GET_MODULE:PyObject*::0:
+PyFunction_GET_MODULE:PyObject*:op:0:
+
PyFunction_New:PyObject*::+1:
PyFunction_New:PyObject*:code:+1:
PyFunction_New:PyObject*:globals:+1:
@@ -1090,6 +1148,9 @@ PyInterpreterState_Clear:PyInterpreterState*:interp::
PyInterpreterState_Delete:void:::
PyInterpreterState_Delete:PyInterpreterState*:interp::
+PyInterpreterState_GetDict:PyObject*::0:
+PyInterpreterState_GetDict:PyInterpreterState*:interp::
+
PyInterpreterState_GetID:int64_t:::
PyInterpreterState_GetID:PyInterpreterState*:interp::
@@ -1269,7 +1330,7 @@ PyMapping_GetItemString:const char*:key::
PyMapping_HasKey:int:::
PyMapping_HasKey:PyObject*:o:0:
-PyMapping_HasKey:PyObject*:key::
+PyMapping_HasKey:PyObject*:key:0:
PyMapping_HasKeyString:int:::
PyMapping_HasKeyString:PyObject*:o:0:
@@ -1429,7 +1490,7 @@ PyModule_GetState:void*:::
PyModule_GetState:PyObject*:module:0:
PyModule_New:PyObject*::+1:
-PyModule_New::char* name::
+PyModule_New:char*:name::
PyModule_NewObject:PyObject*::+1:
PyModule_NewObject:PyObject*:name:+1:
@@ -1439,7 +1500,7 @@ PyModule_SetDocString:PyObject*:module:0:
PyModule_SetDocString:const char*:docstring::
PyModuleDef_Init:PyObject*::0:
-PyModuleDef_Init:PyModuleDef*:def:0:
+PyModuleDef_Init:PyModuleDef*:def::
PyNumber_Absolute:PyObject*::+1:
PyNumber_Absolute:PyObject*:o:0:
@@ -1802,6 +1863,9 @@ PyObject_RichCompareBool:PyObject*:o1:0:
PyObject_RichCompareBool:PyObject*:o2:0:
PyObject_RichCompareBool:int:opid::
+PyObject_SelfIter:PyObject*::+1:
+PyObject_SelfIter:PyObject*:obj:0:
+
PyObject_SetAttr:int:::
PyObject_SetAttr:PyObject*:o:0:
PyObject_SetAttr:PyObject*:attr_name:0:
@@ -1939,10 +2003,10 @@ PyRun_StringFlags:PyObject*:locals:0:
PyRun_StringFlags:PyCompilerFlags*:flags::
PySeqIter_Check:int:::
-PySeqIter_Check::op::
+PySeqIter_Check:PyObject *:op:0:
PySeqIter_New:PyObject*::+1:
-PySeqIter_New:PyObject*:seq::
+PySeqIter_New:PyObject*:seq:0:
PySequence_Check:int:::
PySequence_Check:PyObject*:o:0:
@@ -2334,6 +2398,13 @@ PyType_GetFlags:PyTypeObject*:type:0:
PyType_GetName:PyObject*::+1:
PyType_GetName:PyTypeObject*:type:0:
+PyType_GetModule:PyObject*::0:
+PyType_GetModule:PyTypeObject*:type:0:
+
+PyType_GetModuleByDef:PyObject*::0:
+PyType_GetModuleByDef:PyTypeObject*:type:0:
+PyType_GetModuleByDef:PyModuleDef*:def::
+
PyType_GetQualName:PyObject*::+1:
PyType_GetQualName:PyTypeObject*:type:0:
@@ -2382,7 +2453,7 @@ PyUnicode_GET_DATA_SIZE:PyObject*:o:0:
PyUnicode_KIND:int:::
PyUnicode_KIND:PyObject*:o:0:
-PyUnicode_MAX_CHAR_VALUE::::
+PyUnicode_MAX_CHAR_VALUE:Py_UCS4:::
PyUnicode_MAX_CHAR_VALUE:PyObject*:o:0:
Py_UNICODE_ISALNUM:int:::
@@ -2449,7 +2520,7 @@ PyUnicode_FromWideChar:const wchar_t*:w::
PyUnicode_FromWideChar:Py_ssize_t:size::
PyUnicode_AsWideChar:Py_ssize_t:::
-PyUnicode_AsWideChar:PyObject*:*unicode:0:
+PyUnicode_AsWideChar:PyObject*:unicode:0:
PyUnicode_AsWideChar:wchar_t*:w::
PyUnicode_AsWideChar:Py_ssize_t:size::
@@ -2502,7 +2573,7 @@ PyUnicode_AsUTF8String:PyObject*:unicode:0:
PyUnicode_AsUTF8AndSize:const char*:::
PyUnicode_AsUTF8AndSize:PyObject*:unicode:0:
-PyUnicode_AsUTF8AndSize:Py_ssize_t*:size:0:
+PyUnicode_AsUTF8AndSize:Py_ssize_t*:size::
PyUnicode_AsUTF8:const char*:::
PyUnicode_AsUTF8:PyObject*:unicode:0:
@@ -2585,6 +2656,13 @@ PyUnicode_DecodeMBCSStateful:Py_ssize_t:size::
PyUnicode_DecodeMBCSStateful:const char*:errors::
PyUnicode_DecodeMBCSStateful:Py_ssize_t*:consumed::
+PyUnicode_DecodeCodePageStateful:PyObject*::+1:
+PyUnicode_DecodeCodePageStateful:int:code_page::
+PyUnicode_DecodeCodePageStateful:const char*:s::
+PyUnicode_DecodeCodePageStateful:Py_ssize_t:size::
+PyUnicode_DecodeCodePageStateful:const char*:errors::
+PyUnicode_DecodeCodePageStateful:Py_ssize_t*:consumed::
+
PyUnicode_EncodeCodePage:PyObject*::+1:
PyUnicode_EncodeCodePage:int:code_page::
PyUnicode_EncodeCodePage:PyObject*:unicode:0:
@@ -2597,13 +2675,26 @@ PyUnicode_Concat:PyObject*::+1:
PyUnicode_Concat:PyObject*:left:0:
PyUnicode_Concat:PyObject*:right:0:
+PyUnicode_Partition:PyObject*::+1:
+PyUnicode_Partition:PyObject*:unicode:0:
+PyUnicode_Partition:PyObject*:sep:0:
+
+PyUnicode_RPartition:PyObject*::+1:
+PyUnicode_RPartition:PyObject*:unicode:0:
+PyUnicode_RPartition:PyObject*:sep:0:
+
+PyUnicode_RSplit:PyObject*::+1:
+PyUnicode_RSplit:PyObject*:unicode:0:
+PyUnicode_RSplit:PyObject*:sep:0:
+PyUnicode_RSplit:Py_ssize_t:maxsplit::
+
PyUnicode_Split:PyObject*::+1:
-PyUnicode_Split:PyObject*:left:0:
-PyUnicode_Split:PyObject*:right:0:
+PyUnicode_Split:PyObject*:unicode:0:
+PyUnicode_Split:PyObject*:sep:0:
PyUnicode_Split:Py_ssize_t:maxsplit::
PyUnicode_Splitlines:PyObject*::+1:
-PyUnicode_Splitlines:PyObject*:s:0:
+PyUnicode_Splitlines:PyObject*:unicode:0:
PyUnicode_Splitlines:int:keepend::
PyUnicode_Translate:PyObject*::+1:
@@ -2699,6 +2790,15 @@ PyUnicode_FromFormatV:PyObject*::+1:
PyUnicode_FromFormatV:const char*:format::
PyUnicode_FromFormatV:va_list:args::
+PyUnicode_FromOrdinal:PyObject*::+1:
+PyUnicode_FromOrdinal:int:ordinal::
+
+PyUnicode_BuildEncodingMap:PyObject*::+1:
+PyUnicode_BuildEncodingMap:PyObject*:string:::
+
+PyUnicode_GetDefaultEncoding:const char*:::
+PyUnicode_GetDefaultEncoding::void::
+
PyUnicode_GetLength:Py_ssize_t:::
PyUnicode_GetLength:PyObject*:unicode:0:
@@ -2825,13 +2925,13 @@ PyUnicodeDecodeError_SetStart:PyObject*:exc:0:
PyUnicodeDecodeError_SetStart:Py_ssize_t:start::
PyWeakref_Check:int:::
-PyWeakref_Check:PyObject*:ob::
+PyWeakref_Check:PyObject*:ob:0:
PyWeakref_CheckProxy:int:::
-PyWeakref_CheckProxy:PyObject*:ob::
+PyWeakref_CheckProxy:PyObject*:ob:0:
PyWeakref_CheckRef:int:::
-PyWeakref_CheckRef:PyObject*:ob::
+PyWeakref_CheckRef:PyObject*:ob:0:
PyWeakref_GET_OBJECT:PyObject*::0:
PyWeakref_GET_OBJECT:PyObject*:ref:0:
diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat
index 76a035f194d9115..923742077ea7a2c 100644
--- a/Doc/data/stable_abi.dat
+++ b/Doc/data/stable_abi.dat
@@ -1,891 +1,1031 @@
role,name,added,ifdef_note,struct_abi_kind
+macro,METH_CLASS,3.2,,
+macro,METH_COEXIST,3.2,,
+macro,METH_FASTCALL,3.10,,
+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,,
-function,PyAIter_Check,3.10,,
-function,PyArg_Parse,3.2,,
-function,PyArg_ParseTuple,3.2,,
-function,PyArg_ParseTupleAndKeywords,3.2,,
-function,PyArg_UnpackTuple,3.2,,
-function,PyArg_VaParse,3.2,,
-function,PyArg_VaParseTupleAndKeywords,3.2,,
-function,PyArg_ValidateKeywordArguments,3.2,,
-var,PyBaseObject_Type,3.2,,
-function,PyBool_FromLong,3.2,,
-var,PyBool_Type,3.2,,
-function,PyBuffer_FillContiguousStrides,3.11,,
-function,PyBuffer_FillInfo,3.11,,
-function,PyBuffer_FromContiguous,3.11,,
-function,PyBuffer_GetPointer,3.11,,
-function,PyBuffer_IsContiguous,3.11,,
-function,PyBuffer_Release,3.11,,
-function,PyBuffer_SizeFromFormat,3.11,,
-function,PyBuffer_ToContiguous,3.11,,
-var,PyByteArrayIter_Type,3.2,,
-function,PyByteArray_AsString,3.2,,
-function,PyByteArray_Concat,3.2,,
-function,PyByteArray_FromObject,3.2,,
-function,PyByteArray_FromStringAndSize,3.2,,
-function,PyByteArray_Resize,3.2,,
-function,PyByteArray_Size,3.2,,
-var,PyByteArray_Type,3.2,,
-var,PyBytesIter_Type,3.2,,
-function,PyBytes_AsString,3.2,,
-function,PyBytes_AsStringAndSize,3.2,,
-function,PyBytes_Concat,3.2,,
-function,PyBytes_ConcatAndDel,3.2,,
-function,PyBytes_DecodeEscape,3.2,,
-function,PyBytes_FromFormat,3.2,,
-function,PyBytes_FromFormatV,3.2,,
-function,PyBytes_FromObject,3.2,,
-function,PyBytes_FromString,3.2,,
-function,PyBytes_FromStringAndSize,3.2,,
-function,PyBytes_Repr,3.2,,
-function,PyBytes_Size,3.2,,
-var,PyBytes_Type,3.2,,
+func,PyAIter_Check,3.10,,
+func,PyArg_Parse,3.2,,
+func,PyArg_ParseTuple,3.2,,
+func,PyArg_ParseTupleAndKeywords,3.2,,
+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,,
+func,PyBuffer_FillContiguousStrides,3.11,,
+func,PyBuffer_FillInfo,3.11,,
+func,PyBuffer_FromContiguous,3.11,,
+func,PyBuffer_GetPointer,3.11,,
+func,PyBuffer_IsContiguous,3.11,,
+func,PyBuffer_Release,3.11,,
+func,PyBuffer_SizeFromFormat,3.11,,
+func,PyBuffer_ToContiguous,3.11,,
+data,PyByteArrayIter_Type,3.2,,
+func,PyByteArray_AsString,3.2,,
+func,PyByteArray_Concat,3.2,,
+func,PyByteArray_FromObject,3.2,,
+func,PyByteArray_FromStringAndSize,3.2,,
+func,PyByteArray_Resize,3.2,,
+func,PyByteArray_Size,3.2,,
+data,PyByteArray_Type,3.2,,
+data,PyBytesIter_Type,3.2,,
+func,PyBytes_AsString,3.2,,
+func,PyBytes_AsStringAndSize,3.2,,
+func,PyBytes_Concat,3.2,,
+func,PyBytes_ConcatAndDel,3.2,,
+func,PyBytes_DecodeEscape,3.2,,
+func,PyBytes_FromFormat,3.2,,
+func,PyBytes_FromFormatV,3.2,,
+func,PyBytes_FromObject,3.2,,
+func,PyBytes_FromString,3.2,,
+func,PyBytes_FromStringAndSize,3.2,,
+func,PyBytes_Repr,3.2,,
+func,PyBytes_Size,3.2,,
+data,PyBytes_Type,3.2,,
type,PyCFunction,3.2,,
type,PyCFunctionFast,3.13,,
type,PyCFunctionFastWithKeywords,3.13,,
type,PyCFunctionWithKeywords,3.2,,
-function,PyCFunction_GetFlags,3.2,,
-function,PyCFunction_GetFunction,3.2,,
-function,PyCFunction_GetSelf,3.2,,
-function,PyCFunction_New,3.4,,
-function,PyCFunction_NewEx,3.2,,
-var,PyCFunction_Type,3.2,,
-function,PyCMethod_New,3.9,,
-function,PyCallIter_New,3.2,,
-var,PyCallIter_Type,3.2,,
-function,PyCallable_Check,3.2,,
+func,PyCFunction_GetFlags,3.2,,
+func,PyCFunction_GetFunction,3.2,,
+func,PyCFunction_GetSelf,3.2,,
+func,PyCFunction_New,3.4,,
+func,PyCFunction_NewEx,3.2,,
+data,PyCFunction_Type,3.2,,
+func,PyCMethod_New,3.9,,
+func,PyCallIter_New,3.2,,
+data,PyCallIter_Type,3.2,,
+func,PyCallable_Check,3.2,,
type,PyCapsule_Destructor,3.2,,
-function,PyCapsule_GetContext,3.2,,
-function,PyCapsule_GetDestructor,3.2,,
-function,PyCapsule_GetName,3.2,,
-function,PyCapsule_GetPointer,3.2,,
-function,PyCapsule_Import,3.2,,
-function,PyCapsule_IsValid,3.2,,
-function,PyCapsule_New,3.2,,
-function,PyCapsule_SetContext,3.2,,
-function,PyCapsule_SetDestructor,3.2,,
-function,PyCapsule_SetName,3.2,,
-function,PyCapsule_SetPointer,3.2,,
-var,PyCapsule_Type,3.2,,
-var,PyClassMethodDescr_Type,3.2,,
-function,PyCodec_BackslashReplaceErrors,3.2,,
-function,PyCodec_Decode,3.2,,
-function,PyCodec_Decoder,3.2,,
-function,PyCodec_Encode,3.2,,
-function,PyCodec_Encoder,3.2,,
-function,PyCodec_IgnoreErrors,3.2,,
-function,PyCodec_IncrementalDecoder,3.2,,
-function,PyCodec_IncrementalEncoder,3.2,,
-function,PyCodec_KnownEncoding,3.2,,
-function,PyCodec_LookupError,3.2,,
-function,PyCodec_NameReplaceErrors,3.7,,
-function,PyCodec_Register,3.2,,
-function,PyCodec_RegisterError,3.2,,
-function,PyCodec_ReplaceErrors,3.2,,
-function,PyCodec_StreamReader,3.2,,
-function,PyCodec_StreamWriter,3.2,,
-function,PyCodec_StrictErrors,3.2,,
-function,PyCodec_Unregister,3.10,,
-function,PyCodec_XMLCharRefReplaceErrors,3.2,,
-function,PyComplex_FromDoubles,3.2,,
-function,PyComplex_ImagAsDouble,3.2,,
-function,PyComplex_RealAsDouble,3.2,,
-var,PyComplex_Type,3.2,,
-function,PyDescr_NewClassMethod,3.2,,
-function,PyDescr_NewGetSet,3.2,,
-function,PyDescr_NewMember,3.2,,
-function,PyDescr_NewMethod,3.2,,
-var,PyDictItems_Type,3.2,,
-var,PyDictIterItem_Type,3.2,,
-var,PyDictIterKey_Type,3.2,,
-var,PyDictIterValue_Type,3.2,,
-var,PyDictKeys_Type,3.2,,
-function,PyDictProxy_New,3.2,,
-var,PyDictProxy_Type,3.2,,
-var,PyDictRevIterItem_Type,3.8,,
-var,PyDictRevIterKey_Type,3.8,,
-var,PyDictRevIterValue_Type,3.8,,
-var,PyDictValues_Type,3.2,,
-function,PyDict_Clear,3.2,,
-function,PyDict_Contains,3.2,,
-function,PyDict_Copy,3.2,,
-function,PyDict_DelItem,3.2,,
-function,PyDict_DelItemString,3.2,,
-function,PyDict_GetItem,3.2,,
-function,PyDict_GetItemRef,3.13,,
-function,PyDict_GetItemString,3.2,,
-function,PyDict_GetItemStringRef,3.13,,
-function,PyDict_GetItemWithError,3.2,,
-function,PyDict_Items,3.2,,
-function,PyDict_Keys,3.2,,
-function,PyDict_Merge,3.2,,
-function,PyDict_MergeFromSeq2,3.2,,
-function,PyDict_New,3.2,,
-function,PyDict_Next,3.2,,
-function,PyDict_SetItem,3.2,,
-function,PyDict_SetItemString,3.2,,
-function,PyDict_Size,3.2,,
-var,PyDict_Type,3.2,,
-function,PyDict_Update,3.2,,
-function,PyDict_Values,3.2,,
-var,PyEllipsis_Type,3.2,,
-var,PyEnum_Type,3.2,,
-function,PyErr_BadArgument,3.2,,
-function,PyErr_BadInternalCall,3.2,,
-function,PyErr_CheckSignals,3.2,,
-function,PyErr_Clear,3.2,,
-function,PyErr_Display,3.2,,
-function,PyErr_DisplayException,3.12,,
-function,PyErr_ExceptionMatches,3.2,,
-function,PyErr_Fetch,3.2,,
-function,PyErr_Format,3.2,,
-function,PyErr_FormatV,3.5,,
-function,PyErr_GetExcInfo,3.7,,
-function,PyErr_GetHandledException,3.11,,
-function,PyErr_GetRaisedException,3.12,,
-function,PyErr_GivenExceptionMatches,3.2,,
-function,PyErr_NewException,3.2,,
-function,PyErr_NewExceptionWithDoc,3.2,,
-function,PyErr_NoMemory,3.2,,
-function,PyErr_NormalizeException,3.2,,
-function,PyErr_Occurred,3.2,,
-function,PyErr_Print,3.2,,
-function,PyErr_PrintEx,3.2,,
-function,PyErr_ProgramText,3.2,,
-function,PyErr_ResourceWarning,3.6,,
-function,PyErr_Restore,3.2,,
-function,PyErr_SetExcFromWindowsErr,3.7,on Windows,
-function,PyErr_SetExcFromWindowsErrWithFilename,3.7,on Windows,
-function,PyErr_SetExcFromWindowsErrWithFilenameObject,3.7,on Windows,
-function,PyErr_SetExcFromWindowsErrWithFilenameObjects,3.7,on Windows,
-function,PyErr_SetExcInfo,3.7,,
-function,PyErr_SetFromErrno,3.2,,
-function,PyErr_SetFromErrnoWithFilename,3.2,,
-function,PyErr_SetFromErrnoWithFilenameObject,3.2,,
-function,PyErr_SetFromErrnoWithFilenameObjects,3.7,,
-function,PyErr_SetFromWindowsErr,3.7,on Windows,
-function,PyErr_SetFromWindowsErrWithFilename,3.7,on Windows,
-function,PyErr_SetHandledException,3.11,,
-function,PyErr_SetImportError,3.7,,
-function,PyErr_SetImportErrorSubclass,3.6,,
-function,PyErr_SetInterrupt,3.2,,
-function,PyErr_SetInterruptEx,3.10,,
-function,PyErr_SetNone,3.2,,
-function,PyErr_SetObject,3.2,,
-function,PyErr_SetRaisedException,3.12,,
-function,PyErr_SetString,3.2,,
-function,PyErr_SyntaxLocation,3.2,,
-function,PyErr_SyntaxLocationEx,3.7,,
-function,PyErr_WarnEx,3.2,,
-function,PyErr_WarnExplicit,3.2,,
-function,PyErr_WarnFormat,3.2,,
-function,PyErr_WriteUnraisable,3.2,,
-function,PyEval_AcquireThread,3.2,,
-function,PyEval_EvalCode,3.2,,
-function,PyEval_EvalCodeEx,3.2,,
-function,PyEval_EvalFrame,3.2,,
-function,PyEval_EvalFrameEx,3.2,,
-function,PyEval_GetBuiltins,3.2,,
-function,PyEval_GetFrame,3.2,,
-function,PyEval_GetFrameBuiltins,3.13,,
-function,PyEval_GetFrameGlobals,3.13,,
-function,PyEval_GetFrameLocals,3.13,,
-function,PyEval_GetFuncDesc,3.2,,
-function,PyEval_GetFuncName,3.2,,
-function,PyEval_GetGlobals,3.2,,
-function,PyEval_GetLocals,3.2,,
-function,PyEval_InitThreads,3.2,,
-function,PyEval_ReleaseThread,3.2,,
-function,PyEval_RestoreThread,3.2,,
-function,PyEval_SaveThread,3.2,,
-var,PyExc_ArithmeticError,3.2,,
-var,PyExc_AssertionError,3.2,,
-var,PyExc_AttributeError,3.2,,
-var,PyExc_BaseException,3.2,,
-var,PyExc_BaseExceptionGroup,3.11,,
-var,PyExc_BlockingIOError,3.7,,
-var,PyExc_BrokenPipeError,3.7,,
-var,PyExc_BufferError,3.2,,
-var,PyExc_BytesWarning,3.2,,
-var,PyExc_ChildProcessError,3.7,,
-var,PyExc_ConnectionAbortedError,3.7,,
-var,PyExc_ConnectionError,3.7,,
-var,PyExc_ConnectionRefusedError,3.7,,
-var,PyExc_ConnectionResetError,3.7,,
-var,PyExc_DeprecationWarning,3.2,,
-var,PyExc_EOFError,3.2,,
-var,PyExc_EncodingWarning,3.10,,
-var,PyExc_EnvironmentError,3.2,,
-var,PyExc_Exception,3.2,,
-var,PyExc_FileExistsError,3.7,,
-var,PyExc_FileNotFoundError,3.7,,
-var,PyExc_FloatingPointError,3.2,,
-var,PyExc_FutureWarning,3.2,,
-var,PyExc_GeneratorExit,3.2,,
-var,PyExc_IOError,3.2,,
-var,PyExc_ImportError,3.2,,
-var,PyExc_ImportWarning,3.2,,
-var,PyExc_IncompleteInputError,3.13,,
-var,PyExc_IndentationError,3.2,,
-var,PyExc_IndexError,3.2,,
-var,PyExc_InterruptedError,3.7,,
-var,PyExc_IsADirectoryError,3.7,,
-var,PyExc_KeyError,3.2,,
-var,PyExc_KeyboardInterrupt,3.2,,
-var,PyExc_LookupError,3.2,,
-var,PyExc_MemoryError,3.2,,
-var,PyExc_ModuleNotFoundError,3.6,,
-var,PyExc_NameError,3.2,,
-var,PyExc_NotADirectoryError,3.7,,
-var,PyExc_NotImplementedError,3.2,,
-var,PyExc_OSError,3.2,,
-var,PyExc_OverflowError,3.2,,
-var,PyExc_PendingDeprecationWarning,3.2,,
-var,PyExc_PermissionError,3.7,,
-var,PyExc_ProcessLookupError,3.7,,
-var,PyExc_RecursionError,3.7,,
-var,PyExc_ReferenceError,3.2,,
-var,PyExc_ResourceWarning,3.7,,
-var,PyExc_RuntimeError,3.2,,
-var,PyExc_RuntimeWarning,3.2,,
-var,PyExc_StopAsyncIteration,3.7,,
-var,PyExc_StopIteration,3.2,,
-var,PyExc_SyntaxError,3.2,,
-var,PyExc_SyntaxWarning,3.2,,
-var,PyExc_SystemError,3.2,,
-var,PyExc_SystemExit,3.2,,
-var,PyExc_TabError,3.2,,
-var,PyExc_TimeoutError,3.7,,
-var,PyExc_TypeError,3.2,,
-var,PyExc_UnboundLocalError,3.2,,
-var,PyExc_UnicodeDecodeError,3.2,,
-var,PyExc_UnicodeEncodeError,3.2,,
-var,PyExc_UnicodeError,3.2,,
-var,PyExc_UnicodeTranslateError,3.2,,
-var,PyExc_UnicodeWarning,3.2,,
-var,PyExc_UserWarning,3.2,,
-var,PyExc_ValueError,3.2,,
-var,PyExc_Warning,3.2,,
-var,PyExc_WindowsError,3.7,on Windows,
-var,PyExc_ZeroDivisionError,3.2,,
-function,PyExceptionClass_Name,3.8,,
-function,PyException_GetArgs,3.12,,
-function,PyException_GetCause,3.2,,
-function,PyException_GetContext,3.2,,
-function,PyException_GetTraceback,3.2,,
-function,PyException_SetArgs,3.12,,
-function,PyException_SetCause,3.2,,
-function,PyException_SetContext,3.2,,
-function,PyException_SetTraceback,3.2,,
-function,PyFile_FromFd,3.2,,
-function,PyFile_GetLine,3.2,,
-function,PyFile_WriteObject,3.2,,
-function,PyFile_WriteString,3.2,,
-var,PyFilter_Type,3.2,,
-function,PyFloat_AsDouble,3.2,,
-function,PyFloat_FromDouble,3.2,,
-function,PyFloat_FromString,3.2,,
-function,PyFloat_GetInfo,3.2,,
-function,PyFloat_GetMax,3.2,,
-function,PyFloat_GetMin,3.2,,
-var,PyFloat_Type,3.2,,
+func,PyCapsule_GetContext,3.2,,
+func,PyCapsule_GetDestructor,3.2,,
+func,PyCapsule_GetName,3.2,,
+func,PyCapsule_GetPointer,3.2,,
+func,PyCapsule_Import,3.2,,
+func,PyCapsule_IsValid,3.2,,
+func,PyCapsule_New,3.2,,
+func,PyCapsule_SetContext,3.2,,
+func,PyCapsule_SetDestructor,3.2,,
+func,PyCapsule_SetName,3.2,,
+func,PyCapsule_SetPointer,3.2,,
+data,PyCapsule_Type,3.2,,
+data,PyClassMethodDescr_Type,3.2,,
+func,PyCodec_BackslashReplaceErrors,3.2,,
+func,PyCodec_Decode,3.2,,
+func,PyCodec_Decoder,3.2,,
+func,PyCodec_Encode,3.2,,
+func,PyCodec_Encoder,3.2,,
+func,PyCodec_IgnoreErrors,3.2,,
+func,PyCodec_IncrementalDecoder,3.2,,
+func,PyCodec_IncrementalEncoder,3.2,,
+func,PyCodec_KnownEncoding,3.2,,
+func,PyCodec_LookupError,3.2,,
+func,PyCodec_NameReplaceErrors,3.7,,
+func,PyCodec_Register,3.2,,
+func,PyCodec_RegisterError,3.2,,
+func,PyCodec_ReplaceErrors,3.2,,
+func,PyCodec_StreamReader,3.2,,
+func,PyCodec_StreamWriter,3.2,,
+func,PyCodec_StrictErrors,3.2,,
+func,PyCodec_Unregister,3.10,,
+func,PyCodec_XMLCharRefReplaceErrors,3.2,,
+func,PyComplex_FromDoubles,3.2,,
+func,PyComplex_ImagAsDouble,3.2,,
+func,PyComplex_RealAsDouble,3.2,,
+data,PyComplex_Type,3.2,,
+func,PyDescr_NewClassMethod,3.2,,
+func,PyDescr_NewGetSet,3.2,,
+func,PyDescr_NewMember,3.2,,
+func,PyDescr_NewMethod,3.2,,
+data,PyDictItems_Type,3.2,,
+data,PyDictIterItem_Type,3.2,,
+data,PyDictIterKey_Type,3.2,,
+data,PyDictIterValue_Type,3.2,,
+data,PyDictKeys_Type,3.2,,
+func,PyDictProxy_New,3.2,,
+data,PyDictProxy_Type,3.2,,
+data,PyDictRevIterItem_Type,3.8,,
+data,PyDictRevIterKey_Type,3.8,,
+data,PyDictRevIterValue_Type,3.8,,
+data,PyDictValues_Type,3.2,,
+func,PyDict_Clear,3.2,,
+func,PyDict_Contains,3.2,,
+func,PyDict_Copy,3.2,,
+func,PyDict_DelItem,3.2,,
+func,PyDict_DelItemString,3.2,,
+func,PyDict_GetItem,3.2,,
+func,PyDict_GetItemRef,3.13,,
+func,PyDict_GetItemString,3.2,,
+func,PyDict_GetItemStringRef,3.13,,
+func,PyDict_GetItemWithError,3.2,,
+func,PyDict_Items,3.2,,
+func,PyDict_Keys,3.2,,
+func,PyDict_Merge,3.2,,
+func,PyDict_MergeFromSeq2,3.2,,
+func,PyDict_New,3.2,,
+func,PyDict_Next,3.2,,
+func,PyDict_SetItem,3.2,,
+func,PyDict_SetItemString,3.2,,
+func,PyDict_Size,3.2,,
+data,PyDict_Type,3.2,,
+func,PyDict_Update,3.2,,
+func,PyDict_Values,3.2,,
+data,PyEllipsis_Type,3.2,,
+data,PyEnum_Type,3.2,,
+func,PyErr_BadArgument,3.2,,
+func,PyErr_BadInternalCall,3.2,,
+func,PyErr_CheckSignals,3.2,,
+func,PyErr_Clear,3.2,,
+func,PyErr_Display,3.2,,
+func,PyErr_DisplayException,3.12,,
+func,PyErr_ExceptionMatches,3.2,,
+func,PyErr_Fetch,3.2,,
+func,PyErr_Format,3.2,,
+func,PyErr_FormatV,3.5,,
+func,PyErr_GetExcInfo,3.7,,
+func,PyErr_GetHandledException,3.11,,
+func,PyErr_GetRaisedException,3.12,,
+func,PyErr_GivenExceptionMatches,3.2,,
+func,PyErr_NewException,3.2,,
+func,PyErr_NewExceptionWithDoc,3.2,,
+func,PyErr_NoMemory,3.2,,
+func,PyErr_NormalizeException,3.2,,
+func,PyErr_Occurred,3.2,,
+func,PyErr_Print,3.2,,
+func,PyErr_PrintEx,3.2,,
+func,PyErr_ProgramText,3.2,,
+func,PyErr_ResourceWarning,3.6,,
+func,PyErr_Restore,3.2,,
+func,PyErr_SetExcFromWindowsErr,3.7,on Windows,
+func,PyErr_SetExcFromWindowsErrWithFilename,3.7,on Windows,
+func,PyErr_SetExcFromWindowsErrWithFilenameObject,3.7,on Windows,
+func,PyErr_SetExcFromWindowsErrWithFilenameObjects,3.7,on Windows,
+func,PyErr_SetExcInfo,3.7,,
+func,PyErr_SetFromErrno,3.2,,
+func,PyErr_SetFromErrnoWithFilename,3.2,,
+func,PyErr_SetFromErrnoWithFilenameObject,3.2,,
+func,PyErr_SetFromErrnoWithFilenameObjects,3.7,,
+func,PyErr_SetFromWindowsErr,3.7,on Windows,
+func,PyErr_SetFromWindowsErrWithFilename,3.7,on Windows,
+func,PyErr_SetHandledException,3.11,,
+func,PyErr_SetImportError,3.7,,
+func,PyErr_SetImportErrorSubclass,3.6,,
+func,PyErr_SetInterrupt,3.2,,
+func,PyErr_SetInterruptEx,3.10,,
+func,PyErr_SetNone,3.2,,
+func,PyErr_SetObject,3.2,,
+func,PyErr_SetRaisedException,3.12,,
+func,PyErr_SetString,3.2,,
+func,PyErr_SyntaxLocation,3.2,,
+func,PyErr_SyntaxLocationEx,3.7,,
+func,PyErr_WarnEx,3.2,,
+func,PyErr_WarnExplicit,3.2,,
+func,PyErr_WarnFormat,3.2,,
+func,PyErr_WriteUnraisable,3.2,,
+func,PyEval_AcquireThread,3.2,,
+func,PyEval_EvalCode,3.2,,
+func,PyEval_EvalCodeEx,3.2,,
+func,PyEval_EvalFrame,3.2,,
+func,PyEval_EvalFrameEx,3.2,,
+func,PyEval_GetBuiltins,3.2,,
+func,PyEval_GetFrame,3.2,,
+func,PyEval_GetFrameBuiltins,3.13,,
+func,PyEval_GetFrameGlobals,3.13,,
+func,PyEval_GetFrameLocals,3.13,,
+func,PyEval_GetFuncDesc,3.2,,
+func,PyEval_GetFuncName,3.2,,
+func,PyEval_GetGlobals,3.2,,
+func,PyEval_GetLocals,3.2,,
+func,PyEval_InitThreads,3.2,,
+func,PyEval_ReleaseThread,3.2,,
+func,PyEval_RestoreThread,3.2,,
+func,PyEval_SaveThread,3.2,,
+data,PyExc_ArithmeticError,3.2,,
+data,PyExc_AssertionError,3.2,,
+data,PyExc_AttributeError,3.2,,
+data,PyExc_BaseException,3.2,,
+data,PyExc_BaseExceptionGroup,3.11,,
+data,PyExc_BlockingIOError,3.7,,
+data,PyExc_BrokenPipeError,3.7,,
+data,PyExc_BufferError,3.2,,
+data,PyExc_BytesWarning,3.2,,
+data,PyExc_ChildProcessError,3.7,,
+data,PyExc_ConnectionAbortedError,3.7,,
+data,PyExc_ConnectionError,3.7,,
+data,PyExc_ConnectionRefusedError,3.7,,
+data,PyExc_ConnectionResetError,3.7,,
+data,PyExc_DeprecationWarning,3.2,,
+data,PyExc_EOFError,3.2,,
+data,PyExc_EncodingWarning,3.10,,
+data,PyExc_EnvironmentError,3.2,,
+data,PyExc_Exception,3.2,,
+data,PyExc_FileExistsError,3.7,,
+data,PyExc_FileNotFoundError,3.7,,
+data,PyExc_FloatingPointError,3.2,,
+data,PyExc_FutureWarning,3.2,,
+data,PyExc_GeneratorExit,3.2,,
+data,PyExc_IOError,3.2,,
+data,PyExc_ImportError,3.2,,
+data,PyExc_ImportWarning,3.2,,
+data,PyExc_IndentationError,3.2,,
+data,PyExc_IndexError,3.2,,
+data,PyExc_InterruptedError,3.7,,
+data,PyExc_IsADirectoryError,3.7,,
+data,PyExc_KeyError,3.2,,
+data,PyExc_KeyboardInterrupt,3.2,,
+data,PyExc_LookupError,3.2,,
+data,PyExc_MemoryError,3.2,,
+data,PyExc_ModuleNotFoundError,3.6,,
+data,PyExc_NameError,3.2,,
+data,PyExc_NotADirectoryError,3.7,,
+data,PyExc_NotImplementedError,3.2,,
+data,PyExc_OSError,3.2,,
+data,PyExc_OverflowError,3.2,,
+data,PyExc_PendingDeprecationWarning,3.2,,
+data,PyExc_PermissionError,3.7,,
+data,PyExc_ProcessLookupError,3.7,,
+data,PyExc_RecursionError,3.7,,
+data,PyExc_ReferenceError,3.2,,
+data,PyExc_ResourceWarning,3.7,,
+data,PyExc_RuntimeError,3.2,,
+data,PyExc_RuntimeWarning,3.2,,
+data,PyExc_StopAsyncIteration,3.7,,
+data,PyExc_StopIteration,3.2,,
+data,PyExc_SyntaxError,3.2,,
+data,PyExc_SyntaxWarning,3.2,,
+data,PyExc_SystemError,3.2,,
+data,PyExc_SystemExit,3.2,,
+data,PyExc_TabError,3.2,,
+data,PyExc_TimeoutError,3.7,,
+data,PyExc_TypeError,3.2,,
+data,PyExc_UnboundLocalError,3.2,,
+data,PyExc_UnicodeDecodeError,3.2,,
+data,PyExc_UnicodeEncodeError,3.2,,
+data,PyExc_UnicodeError,3.2,,
+data,PyExc_UnicodeTranslateError,3.2,,
+data,PyExc_UnicodeWarning,3.2,,
+data,PyExc_UserWarning,3.2,,
+data,PyExc_ValueError,3.2,,
+data,PyExc_Warning,3.2,,
+data,PyExc_WindowsError,3.7,on Windows,
+data,PyExc_ZeroDivisionError,3.2,,
+func,PyExceptionClass_Name,3.8,,
+func,PyException_GetArgs,3.12,,
+func,PyException_GetCause,3.2,,
+func,PyException_GetContext,3.2,,
+func,PyException_GetTraceback,3.2,,
+func,PyException_SetArgs,3.12,,
+func,PyException_SetCause,3.2,,
+func,PyException_SetContext,3.2,,
+func,PyException_SetTraceback,3.2,,
+func,PyFile_FromFd,3.2,,
+func,PyFile_GetLine,3.2,,
+func,PyFile_WriteObject,3.2,,
+func,PyFile_WriteString,3.2,,
+data,PyFilter_Type,3.2,,
+func,PyFloat_AsDouble,3.2,,
+func,PyFloat_FromDouble,3.2,,
+func,PyFloat_FromString,3.2,,
+func,PyFloat_GetInfo,3.2,,
+func,PyFloat_GetMax,3.2,,
+func,PyFloat_GetMin,3.2,,
+data,PyFloat_Type,3.2,,
type,PyFrameObject,3.2,,opaque
-function,PyFrame_GetCode,3.10,,
-function,PyFrame_GetLineNumber,3.10,,
-function,PyFrozenSet_New,3.2,,
-var,PyFrozenSet_Type,3.2,,
-function,PyGC_Collect,3.2,,
-function,PyGC_Disable,3.10,,
-function,PyGC_Enable,3.10,,
-function,PyGC_IsEnabled,3.10,,
-function,PyGILState_Ensure,3.2,,
-function,PyGILState_GetThisThreadState,3.2,,
-function,PyGILState_Release,3.2,,
+func,PyFrame_GetCode,3.10,,
+func,PyFrame_GetLineNumber,3.10,,
+func,PyFrozenSet_New,3.2,,
+data,PyFrozenSet_Type,3.2,,
+func,PyGC_Collect,3.2,,
+func,PyGC_Disable,3.10,,
+func,PyGC_Enable,3.10,,
+func,PyGC_IsEnabled,3.10,,
+func,PyGILState_Ensure,3.2,,
+func,PyGILState_GetThisThreadState,3.2,,
+func,PyGILState_Release,3.2,,
type,PyGILState_STATE,3.2,,
type,PyGetSetDef,3.2,,full-abi
-var,PyGetSetDescr_Type,3.2,,
-function,PyImport_AddModule,3.2,,
-function,PyImport_AddModuleObject,3.7,,
-function,PyImport_AddModuleRef,3.13,,
-function,PyImport_AppendInittab,3.2,,
-function,PyImport_ExecCodeModule,3.2,,
-function,PyImport_ExecCodeModuleEx,3.2,,
-function,PyImport_ExecCodeModuleObject,3.7,,
-function,PyImport_ExecCodeModuleWithPathnames,3.2,,
-function,PyImport_GetImporter,3.2,,
-function,PyImport_GetMagicNumber,3.2,,
-function,PyImport_GetMagicTag,3.2,,
-function,PyImport_GetModule,3.8,,
-function,PyImport_GetModuleDict,3.2,,
-function,PyImport_Import,3.2,,
-function,PyImport_ImportFrozenModule,3.2,,
-function,PyImport_ImportFrozenModuleObject,3.7,,
-function,PyImport_ImportModule,3.2,,
-function,PyImport_ImportModuleLevel,3.2,,
-function,PyImport_ImportModuleLevelObject,3.7,,
-function,PyImport_ImportModuleNoBlock,3.2,,
-function,PyImport_ReloadModule,3.2,,
-function,PyIndex_Check,3.8,,
+data,PyGetSetDescr_Type,3.2,,
+func,PyImport_AddModule,3.2,,
+func,PyImport_AddModuleObject,3.7,,
+func,PyImport_AddModuleRef,3.13,,
+func,PyImport_AppendInittab,3.2,,
+func,PyImport_ExecCodeModule,3.2,,
+func,PyImport_ExecCodeModuleEx,3.2,,
+func,PyImport_ExecCodeModuleObject,3.7,,
+func,PyImport_ExecCodeModuleWithPathnames,3.2,,
+func,PyImport_GetImporter,3.2,,
+func,PyImport_GetMagicNumber,3.2,,
+func,PyImport_GetMagicTag,3.2,,
+func,PyImport_GetModule,3.8,,
+func,PyImport_GetModuleDict,3.2,,
+func,PyImport_Import,3.2,,
+func,PyImport_ImportFrozenModule,3.2,,
+func,PyImport_ImportFrozenModuleObject,3.7,,
+func,PyImport_ImportModule,3.2,,
+func,PyImport_ImportModuleLevel,3.2,,
+func,PyImport_ImportModuleLevelObject,3.7,,
+func,PyImport_ImportModuleNoBlock,3.2,,
+func,PyImport_ReloadModule,3.2,,
+func,PyIndex_Check,3.8,,
type,PyInterpreterState,3.2,,opaque
-function,PyInterpreterState_Clear,3.2,,
-function,PyInterpreterState_Delete,3.2,,
-function,PyInterpreterState_Get,3.9,,
-function,PyInterpreterState_GetDict,3.8,,
-function,PyInterpreterState_GetID,3.7,,
-function,PyInterpreterState_New,3.2,,
-function,PyIter_Check,3.8,,
-function,PyIter_Next,3.2,,
-function,PyIter_Send,3.10,,
-var,PyListIter_Type,3.2,,
-var,PyListRevIter_Type,3.2,,
-function,PyList_Append,3.2,,
-function,PyList_AsTuple,3.2,,
-function,PyList_GetItem,3.2,,
-function,PyList_GetItemRef,3.13,,
-function,PyList_GetSlice,3.2,,
-function,PyList_Insert,3.2,,
-function,PyList_New,3.2,,
-function,PyList_Reverse,3.2,,
-function,PyList_SetItem,3.2,,
-function,PyList_SetSlice,3.2,,
-function,PyList_Size,3.2,,
-function,PyList_Sort,3.2,,
-var,PyList_Type,3.2,,
+func,PyInterpreterState_Clear,3.2,,
+func,PyInterpreterState_Delete,3.2,,
+func,PyInterpreterState_Get,3.9,,
+func,PyInterpreterState_GetDict,3.8,,
+func,PyInterpreterState_GetID,3.7,,
+func,PyInterpreterState_New,3.2,,
+func,PyIter_Check,3.8,,
+func,PyIter_Next,3.2,,
+func,PyIter_Send,3.10,,
+data,PyListIter_Type,3.2,,
+data,PyListRevIter_Type,3.2,,
+func,PyList_Append,3.2,,
+func,PyList_AsTuple,3.2,,
+func,PyList_GetItem,3.2,,
+func,PyList_GetItemRef,3.13,,
+func,PyList_GetSlice,3.2,,
+func,PyList_Insert,3.2,,
+func,PyList_New,3.2,,
+func,PyList_Reverse,3.2,,
+func,PyList_SetItem,3.2,,
+func,PyList_SetSlice,3.2,,
+func,PyList_Size,3.2,,
+func,PyList_Sort,3.2,,
+data,PyList_Type,3.2,,
type,PyLongObject,3.2,,opaque
-var,PyLongRangeIter_Type,3.2,,
-function,PyLong_AsDouble,3.2,,
-function,PyLong_AsInt,3.13,,
-function,PyLong_AsLong,3.2,,
-function,PyLong_AsLongAndOverflow,3.2,,
-function,PyLong_AsLongLong,3.2,,
-function,PyLong_AsLongLongAndOverflow,3.2,,
-function,PyLong_AsSize_t,3.2,,
-function,PyLong_AsSsize_t,3.2,,
-function,PyLong_AsUnsignedLong,3.2,,
-function,PyLong_AsUnsignedLongLong,3.2,,
-function,PyLong_AsUnsignedLongLongMask,3.2,,
-function,PyLong_AsUnsignedLongMask,3.2,,
-function,PyLong_AsVoidPtr,3.2,,
-function,PyLong_FromDouble,3.2,,
-function,PyLong_FromLong,3.2,,
-function,PyLong_FromLongLong,3.2,,
-function,PyLong_FromSize_t,3.2,,
-function,PyLong_FromSsize_t,3.2,,
-function,PyLong_FromString,3.2,,
-function,PyLong_FromUnsignedLong,3.2,,
-function,PyLong_FromUnsignedLongLong,3.2,,
-function,PyLong_FromVoidPtr,3.2,,
-function,PyLong_GetInfo,3.2,,
-var,PyLong_Type,3.2,,
-var,PyMap_Type,3.2,,
-function,PyMapping_Check,3.2,,
-function,PyMapping_GetItemString,3.2,,
-function,PyMapping_GetOptionalItem,3.13,,
-function,PyMapping_GetOptionalItemString,3.13,,
-function,PyMapping_HasKey,3.2,,
-function,PyMapping_HasKeyString,3.2,,
-function,PyMapping_HasKeyStringWithError,3.13,,
-function,PyMapping_HasKeyWithError,3.13,,
-function,PyMapping_Items,3.2,,
-function,PyMapping_Keys,3.2,,
-function,PyMapping_Length,3.2,,
-function,PyMapping_SetItemString,3.2,,
-function,PyMapping_Size,3.2,,
-function,PyMapping_Values,3.2,,
-function,PyMem_Calloc,3.7,,
-function,PyMem_Free,3.2,,
-function,PyMem_Malloc,3.2,,
-function,PyMem_RawCalloc,3.13,,
-function,PyMem_RawFree,3.13,,
-function,PyMem_RawMalloc,3.13,,
-function,PyMem_RawRealloc,3.13,,
-function,PyMem_Realloc,3.2,,
+data,PyLongRangeIter_Type,3.2,,
+func,PyLong_AsDouble,3.2,,
+func,PyLong_AsInt,3.13,,
+func,PyLong_AsLong,3.2,,
+func,PyLong_AsLongAndOverflow,3.2,,
+func,PyLong_AsLongLong,3.2,,
+func,PyLong_AsLongLongAndOverflow,3.2,,
+func,PyLong_AsSize_t,3.2,,
+func,PyLong_AsSsize_t,3.2,,
+func,PyLong_AsUnsignedLong,3.2,,
+func,PyLong_AsUnsignedLongLong,3.2,,
+func,PyLong_AsUnsignedLongLongMask,3.2,,
+func,PyLong_AsUnsignedLongMask,3.2,,
+func,PyLong_AsVoidPtr,3.2,,
+func,PyLong_FromDouble,3.2,,
+func,PyLong_FromLong,3.2,,
+func,PyLong_FromLongLong,3.2,,
+func,PyLong_FromSize_t,3.2,,
+func,PyLong_FromSsize_t,3.2,,
+func,PyLong_FromString,3.2,,
+func,PyLong_FromUnsignedLong,3.2,,
+func,PyLong_FromUnsignedLongLong,3.2,,
+func,PyLong_FromVoidPtr,3.2,,
+func,PyLong_GetInfo,3.2,,
+data,PyLong_Type,3.2,,
+data,PyMap_Type,3.2,,
+func,PyMapping_Check,3.2,,
+func,PyMapping_GetItemString,3.2,,
+func,PyMapping_GetOptionalItem,3.13,,
+func,PyMapping_GetOptionalItemString,3.13,,
+func,PyMapping_HasKey,3.2,,
+func,PyMapping_HasKeyString,3.2,,
+func,PyMapping_HasKeyStringWithError,3.13,,
+func,PyMapping_HasKeyWithError,3.13,,
+func,PyMapping_Items,3.2,,
+func,PyMapping_Keys,3.2,,
+func,PyMapping_Length,3.2,,
+func,PyMapping_SetItemString,3.2,,
+func,PyMapping_Size,3.2,,
+func,PyMapping_Values,3.2,,
+func,PyMem_Calloc,3.7,,
+func,PyMem_Free,3.2,,
+func,PyMem_Malloc,3.2,,
+func,PyMem_RawCalloc,3.13,,
+func,PyMem_RawFree,3.13,,
+func,PyMem_RawMalloc,3.13,,
+func,PyMem_RawRealloc,3.13,,
+func,PyMem_Realloc,3.2,,
type,PyMemberDef,3.2,,full-abi
-var,PyMemberDescr_Type,3.2,,
-function,PyMember_GetOne,3.2,,
-function,PyMember_SetOne,3.2,,
-function,PyMemoryView_FromBuffer,3.11,,
-function,PyMemoryView_FromMemory,3.7,,
-function,PyMemoryView_FromObject,3.2,,
-function,PyMemoryView_GetContiguous,3.2,,
-var,PyMemoryView_Type,3.2,,
+data,PyMemberDescr_Type,3.2,,
+func,PyMember_GetOne,3.2,,
+func,PyMember_SetOne,3.2,,
+func,PyMemoryView_FromBuffer,3.11,,
+func,PyMemoryView_FromMemory,3.7,,
+func,PyMemoryView_FromObject,3.2,,
+func,PyMemoryView_GetContiguous,3.2,,
+data,PyMemoryView_Type,3.2,,
type,PyMethodDef,3.2,,full-abi
-var,PyMethodDescr_Type,3.2,,
+data,PyMethodDescr_Type,3.2,,
type,PyModuleDef,3.2,,full-abi
type,PyModuleDef_Base,3.2,,full-abi
-function,PyModuleDef_Init,3.5,,
-var,PyModuleDef_Type,3.5,,
-function,PyModule_Add,3.13,,
-function,PyModule_AddFunctions,3.7,,
-function,PyModule_AddIntConstant,3.2,,
-function,PyModule_AddObject,3.2,,
-function,PyModule_AddObjectRef,3.10,,
-function,PyModule_AddStringConstant,3.2,,
-function,PyModule_AddType,3.10,,
-function,PyModule_Create2,3.2,,
-function,PyModule_ExecDef,3.7,,
-function,PyModule_FromDefAndSpec2,3.7,,
-function,PyModule_GetDef,3.2,,
-function,PyModule_GetDict,3.2,,
-function,PyModule_GetFilename,3.2,,
-function,PyModule_GetFilenameObject,3.2,,
-function,PyModule_GetName,3.2,,
-function,PyModule_GetNameObject,3.7,,
-function,PyModule_GetState,3.2,,
-function,PyModule_New,3.2,,
-function,PyModule_NewObject,3.7,,
-function,PyModule_SetDocString,3.7,,
-var,PyModule_Type,3.2,,
-function,PyNumber_Absolute,3.2,,
-function,PyNumber_Add,3.2,,
-function,PyNumber_And,3.2,,
-function,PyNumber_AsSsize_t,3.2,,
-function,PyNumber_Check,3.2,,
-function,PyNumber_Divmod,3.2,,
-function,PyNumber_Float,3.2,,
-function,PyNumber_FloorDivide,3.2,,
-function,PyNumber_InPlaceAdd,3.2,,
-function,PyNumber_InPlaceAnd,3.2,,
-function,PyNumber_InPlaceFloorDivide,3.2,,
-function,PyNumber_InPlaceLshift,3.2,,
-function,PyNumber_InPlaceMatrixMultiply,3.7,,
-function,PyNumber_InPlaceMultiply,3.2,,
-function,PyNumber_InPlaceOr,3.2,,
-function,PyNumber_InPlacePower,3.2,,
-function,PyNumber_InPlaceRemainder,3.2,,
-function,PyNumber_InPlaceRshift,3.2,,
-function,PyNumber_InPlaceSubtract,3.2,,
-function,PyNumber_InPlaceTrueDivide,3.2,,
-function,PyNumber_InPlaceXor,3.2,,
-function,PyNumber_Index,3.2,,
-function,PyNumber_Invert,3.2,,
-function,PyNumber_Long,3.2,,
-function,PyNumber_Lshift,3.2,,
-function,PyNumber_MatrixMultiply,3.7,,
-function,PyNumber_Multiply,3.2,,
-function,PyNumber_Negative,3.2,,
-function,PyNumber_Or,3.2,,
-function,PyNumber_Positive,3.2,,
-function,PyNumber_Power,3.2,,
-function,PyNumber_Remainder,3.2,,
-function,PyNumber_Rshift,3.2,,
-function,PyNumber_Subtract,3.2,,
-function,PyNumber_ToBase,3.2,,
-function,PyNumber_TrueDivide,3.2,,
-function,PyNumber_Xor,3.2,,
-function,PyOS_AfterFork,3.2,on platforms with fork(),
-function,PyOS_AfterFork_Child,3.7,on platforms with fork(),
-function,PyOS_AfterFork_Parent,3.7,on platforms with fork(),
-function,PyOS_BeforeFork,3.7,on platforms with fork(),
-function,PyOS_CheckStack,3.7,on platforms with USE_STACKCHECK,
-function,PyOS_FSPath,3.6,,
-var,PyOS_InputHook,3.2,,
-function,PyOS_InterruptOccurred,3.2,,
-function,PyOS_double_to_string,3.2,,
-function,PyOS_getsig,3.2,,
-function,PyOS_mystricmp,3.2,,
-function,PyOS_mystrnicmp,3.2,,
-function,PyOS_setsig,3.2,,
+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,,
+func,PyModule_AddIntConstant,3.2,,
+func,PyModule_AddObject,3.2,,
+func,PyModule_AddObjectRef,3.10,,
+func,PyModule_AddStringConstant,3.2,,
+func,PyModule_AddType,3.10,,
+func,PyModule_Create2,3.2,,
+func,PyModule_ExecDef,3.7,,
+func,PyModule_FromDefAndSpec2,3.7,,
+func,PyModule_GetDef,3.2,,
+func,PyModule_GetDict,3.2,,
+func,PyModule_GetFilename,3.2,,
+func,PyModule_GetFilenameObject,3.2,,
+func,PyModule_GetName,3.2,,
+func,PyModule_GetNameObject,3.7,,
+func,PyModule_GetState,3.2,,
+func,PyModule_New,3.2,,
+func,PyModule_NewObject,3.7,,
+func,PyModule_SetDocString,3.7,,
+data,PyModule_Type,3.2,,
+func,PyNumber_Absolute,3.2,,
+func,PyNumber_Add,3.2,,
+func,PyNumber_And,3.2,,
+func,PyNumber_AsSsize_t,3.2,,
+func,PyNumber_Check,3.2,,
+func,PyNumber_Divmod,3.2,,
+func,PyNumber_Float,3.2,,
+func,PyNumber_FloorDivide,3.2,,
+func,PyNumber_InPlaceAdd,3.2,,
+func,PyNumber_InPlaceAnd,3.2,,
+func,PyNumber_InPlaceFloorDivide,3.2,,
+func,PyNumber_InPlaceLshift,3.2,,
+func,PyNumber_InPlaceMatrixMultiply,3.7,,
+func,PyNumber_InPlaceMultiply,3.2,,
+func,PyNumber_InPlaceOr,3.2,,
+func,PyNumber_InPlacePower,3.2,,
+func,PyNumber_InPlaceRemainder,3.2,,
+func,PyNumber_InPlaceRshift,3.2,,
+func,PyNumber_InPlaceSubtract,3.2,,
+func,PyNumber_InPlaceTrueDivide,3.2,,
+func,PyNumber_InPlaceXor,3.2,,
+func,PyNumber_Index,3.2,,
+func,PyNumber_Invert,3.2,,
+func,PyNumber_Long,3.2,,
+func,PyNumber_Lshift,3.2,,
+func,PyNumber_MatrixMultiply,3.7,,
+func,PyNumber_Multiply,3.2,,
+func,PyNumber_Negative,3.2,,
+func,PyNumber_Or,3.2,,
+func,PyNumber_Positive,3.2,,
+func,PyNumber_Power,3.2,,
+func,PyNumber_Remainder,3.2,,
+func,PyNumber_Rshift,3.2,,
+func,PyNumber_Subtract,3.2,,
+func,PyNumber_ToBase,3.2,,
+func,PyNumber_TrueDivide,3.2,,
+func,PyNumber_Xor,3.2,,
+func,PyOS_AfterFork,3.2,on platforms with fork(),
+func,PyOS_AfterFork_Child,3.7,on platforms with fork(),
+func,PyOS_AfterFork_Parent,3.7,on platforms with fork(),
+func,PyOS_BeforeFork,3.7,on platforms with fork(),
+func,PyOS_CheckStack,3.7,on platforms with USE_STACKCHECK,
+func,PyOS_FSPath,3.6,,
+data,PyOS_InputHook,3.2,,
+func,PyOS_InterruptOccurred,3.2,,
+func,PyOS_double_to_string,3.2,,
+func,PyOS_getsig,3.2,,
+func,PyOS_mystricmp,3.2,,
+func,PyOS_mystrnicmp,3.2,,
+func,PyOS_setsig,3.2,,
type,PyOS_sighandler_t,3.2,,
-function,PyOS_snprintf,3.2,,
-function,PyOS_string_to_double,3.2,,
-function,PyOS_strtol,3.2,,
-function,PyOS_strtoul,3.2,,
-function,PyOS_vsnprintf,3.2,,
+func,PyOS_snprintf,3.2,,
+func,PyOS_string_to_double,3.2,,
+func,PyOS_strtol,3.2,,
+func,PyOS_strtoul,3.2,,
+func,PyOS_vsnprintf,3.2,,
type,PyObject,3.2,,members
member,PyObject.ob_refcnt,3.2,,
member,PyObject.ob_type,3.2,,
-function,PyObject_ASCII,3.2,,
-function,PyObject_AsFileDescriptor,3.2,,
-function,PyObject_Bytes,3.2,,
-function,PyObject_Call,3.2,,
-function,PyObject_CallFunction,3.2,,
-function,PyObject_CallFunctionObjArgs,3.2,,
-function,PyObject_CallMethod,3.2,,
-function,PyObject_CallMethodObjArgs,3.2,,
-function,PyObject_CallNoArgs,3.10,,
-function,PyObject_CallObject,3.2,,
-function,PyObject_Calloc,3.7,,
-function,PyObject_CheckBuffer,3.11,,
-function,PyObject_ClearWeakRefs,3.2,,
-function,PyObject_CopyData,3.11,,
-function,PyObject_DelAttr,3.13,,
-function,PyObject_DelAttrString,3.13,,
-function,PyObject_DelItem,3.2,,
-function,PyObject_DelItemString,3.2,,
-function,PyObject_Dir,3.2,,
-function,PyObject_Format,3.2,,
-function,PyObject_Free,3.2,,
-function,PyObject_GC_Del,3.2,,
-function,PyObject_GC_IsFinalized,3.9,,
-function,PyObject_GC_IsTracked,3.9,,
-function,PyObject_GC_Track,3.2,,
-function,PyObject_GC_UnTrack,3.2,,
-function,PyObject_GenericGetAttr,3.2,,
-function,PyObject_GenericGetDict,3.10,,
-function,PyObject_GenericSetAttr,3.2,,
-function,PyObject_GenericSetDict,3.7,,
-function,PyObject_GetAIter,3.10,,
-function,PyObject_GetAttr,3.2,,
-function,PyObject_GetAttrString,3.2,,
-function,PyObject_GetBuffer,3.11,,
-function,PyObject_GetItem,3.2,,
-function,PyObject_GetIter,3.2,,
-function,PyObject_GetOptionalAttr,3.13,,
-function,PyObject_GetOptionalAttrString,3.13,,
-function,PyObject_GetTypeData,3.12,,
-function,PyObject_HasAttr,3.2,,
-function,PyObject_HasAttrString,3.2,,
-function,PyObject_HasAttrStringWithError,3.13,,
-function,PyObject_HasAttrWithError,3.13,,
-function,PyObject_Hash,3.2,,
-function,PyObject_HashNotImplemented,3.2,,
-function,PyObject_Init,3.2,,
-function,PyObject_InitVar,3.2,,
-function,PyObject_IsInstance,3.2,,
-function,PyObject_IsSubclass,3.2,,
-function,PyObject_IsTrue,3.2,,
-function,PyObject_Length,3.2,,
-function,PyObject_Malloc,3.2,,
-function,PyObject_Not,3.2,,
-function,PyObject_Realloc,3.2,,
-function,PyObject_Repr,3.2,,
-function,PyObject_RichCompare,3.2,,
-function,PyObject_RichCompareBool,3.2,,
-function,PyObject_SelfIter,3.2,,
-function,PyObject_SetAttr,3.2,,
-function,PyObject_SetAttrString,3.2,,
-function,PyObject_SetItem,3.2,,
-function,PyObject_Size,3.2,,
-function,PyObject_Str,3.2,,
-function,PyObject_Type,3.2,,
-function,PyObject_Vectorcall,3.12,,
-function,PyObject_VectorcallMethod,3.12,,
-var,PyProperty_Type,3.2,,
-var,PyRangeIter_Type,3.2,,
-var,PyRange_Type,3.2,,
-var,PyReversed_Type,3.2,,
-function,PySeqIter_New,3.2,,
-var,PySeqIter_Type,3.2,,
-function,PySequence_Check,3.2,,
-function,PySequence_Concat,3.2,,
-function,PySequence_Contains,3.2,,
-function,PySequence_Count,3.2,,
-function,PySequence_DelItem,3.2,,
-function,PySequence_DelSlice,3.2,,
-function,PySequence_Fast,3.2,,
-function,PySequence_GetItem,3.2,,
-function,PySequence_GetSlice,3.2,,
-function,PySequence_In,3.2,,
-function,PySequence_InPlaceConcat,3.2,,
-function,PySequence_InPlaceRepeat,3.2,,
-function,PySequence_Index,3.2,,
-function,PySequence_Length,3.2,,
-function,PySequence_List,3.2,,
-function,PySequence_Repeat,3.2,,
-function,PySequence_SetItem,3.2,,
-function,PySequence_SetSlice,3.2,,
-function,PySequence_Size,3.2,,
-function,PySequence_Tuple,3.2,,
-var,PySetIter_Type,3.2,,
-function,PySet_Add,3.2,,
-function,PySet_Clear,3.2,,
-function,PySet_Contains,3.2,,
-function,PySet_Discard,3.2,,
-function,PySet_New,3.2,,
-function,PySet_Pop,3.2,,
-function,PySet_Size,3.2,,
-var,PySet_Type,3.2,,
-function,PySlice_AdjustIndices,3.7,,
-function,PySlice_GetIndices,3.2,,
-function,PySlice_GetIndicesEx,3.2,,
-function,PySlice_New,3.2,,
-var,PySlice_Type,3.2,,
-function,PySlice_Unpack,3.7,,
-function,PyState_AddModule,3.3,,
-function,PyState_FindModule,3.2,,
-function,PyState_RemoveModule,3.3,,
+func,PyObject_ASCII,3.2,,
+func,PyObject_AsFileDescriptor,3.2,,
+func,PyObject_Bytes,3.2,,
+func,PyObject_Call,3.2,,
+func,PyObject_CallFunction,3.2,,
+func,PyObject_CallFunctionObjArgs,3.2,,
+func,PyObject_CallMethod,3.2,,
+func,PyObject_CallMethodObjArgs,3.2,,
+func,PyObject_CallNoArgs,3.10,,
+func,PyObject_CallObject,3.2,,
+func,PyObject_Calloc,3.7,,
+func,PyObject_CheckBuffer,3.11,,
+func,PyObject_ClearWeakRefs,3.2,,
+func,PyObject_CopyData,3.11,,
+func,PyObject_DelAttr,3.13,,
+func,PyObject_DelAttrString,3.13,,
+func,PyObject_DelItem,3.2,,
+func,PyObject_DelItemString,3.2,,
+func,PyObject_Dir,3.2,,
+func,PyObject_Format,3.2,,
+func,PyObject_Free,3.2,,
+func,PyObject_GC_Del,3.2,,
+func,PyObject_GC_IsFinalized,3.9,,
+func,PyObject_GC_IsTracked,3.9,,
+func,PyObject_GC_Track,3.2,,
+func,PyObject_GC_UnTrack,3.2,,
+func,PyObject_GenericGetAttr,3.2,,
+func,PyObject_GenericGetDict,3.10,,
+func,PyObject_GenericSetAttr,3.2,,
+func,PyObject_GenericSetDict,3.7,,
+func,PyObject_GetAIter,3.10,,
+func,PyObject_GetAttr,3.2,,
+func,PyObject_GetAttrString,3.2,,
+func,PyObject_GetBuffer,3.11,,
+func,PyObject_GetItem,3.2,,
+func,PyObject_GetIter,3.2,,
+func,PyObject_GetOptionalAttr,3.13,,
+func,PyObject_GetOptionalAttrString,3.13,,
+func,PyObject_GetTypeData,3.12,,
+func,PyObject_HasAttr,3.2,,
+func,PyObject_HasAttrString,3.2,,
+func,PyObject_HasAttrStringWithError,3.13,,
+func,PyObject_HasAttrWithError,3.13,,
+func,PyObject_Hash,3.2,,
+func,PyObject_HashNotImplemented,3.2,,
+func,PyObject_Init,3.2,,
+func,PyObject_InitVar,3.2,,
+func,PyObject_IsInstance,3.2,,
+func,PyObject_IsSubclass,3.2,,
+func,PyObject_IsTrue,3.2,,
+func,PyObject_Length,3.2,,
+func,PyObject_Malloc,3.2,,
+func,PyObject_Not,3.2,,
+func,PyObject_Realloc,3.2,,
+func,PyObject_Repr,3.2,,
+func,PyObject_RichCompare,3.2,,
+func,PyObject_RichCompareBool,3.2,,
+func,PyObject_SelfIter,3.2,,
+func,PyObject_SetAttr,3.2,,
+func,PyObject_SetAttrString,3.2,,
+func,PyObject_SetItem,3.2,,
+func,PyObject_Size,3.2,,
+func,PyObject_Str,3.2,,
+func,PyObject_Type,3.2,,
+func,PyObject_Vectorcall,3.12,,
+func,PyObject_VectorcallMethod,3.12,,
+data,PyProperty_Type,3.2,,
+data,PyRangeIter_Type,3.2,,
+data,PyRange_Type,3.2,,
+data,PyReversed_Type,3.2,,
+func,PySeqIter_New,3.2,,
+data,PySeqIter_Type,3.2,,
+func,PySequence_Check,3.2,,
+func,PySequence_Concat,3.2,,
+func,PySequence_Contains,3.2,,
+func,PySequence_Count,3.2,,
+func,PySequence_DelItem,3.2,,
+func,PySequence_DelSlice,3.2,,
+func,PySequence_Fast,3.2,,
+func,PySequence_GetItem,3.2,,
+func,PySequence_GetSlice,3.2,,
+func,PySequence_In,3.2,,
+func,PySequence_InPlaceConcat,3.2,,
+func,PySequence_InPlaceRepeat,3.2,,
+func,PySequence_Index,3.2,,
+func,PySequence_Length,3.2,,
+func,PySequence_List,3.2,,
+func,PySequence_Repeat,3.2,,
+func,PySequence_SetItem,3.2,,
+func,PySequence_SetSlice,3.2,,
+func,PySequence_Size,3.2,,
+func,PySequence_Tuple,3.2,,
+data,PySetIter_Type,3.2,,
+func,PySet_Add,3.2,,
+func,PySet_Clear,3.2,,
+func,PySet_Contains,3.2,,
+func,PySet_Discard,3.2,,
+func,PySet_New,3.2,,
+func,PySet_Pop,3.2,,
+func,PySet_Size,3.2,,
+data,PySet_Type,3.2,,
+func,PySlice_AdjustIndices,3.7,,
+func,PySlice_GetIndices,3.2,,
+func,PySlice_GetIndicesEx,3.2,,
+func,PySlice_New,3.2,,
+data,PySlice_Type,3.2,,
+func,PySlice_Unpack,3.7,,
+func,PyState_AddModule,3.3,,
+func,PyState_FindModule,3.2,,
+func,PyState_RemoveModule,3.3,,
type,PyStructSequence_Desc,3.2,,full-abi
type,PyStructSequence_Field,3.2,,full-abi
-function,PyStructSequence_GetItem,3.2,,
-function,PyStructSequence_New,3.2,,
-function,PyStructSequence_NewType,3.2,,
-function,PyStructSequence_SetItem,3.2,,
-var,PyStructSequence_UnnamedField,3.11,,
-var,PySuper_Type,3.2,,
-function,PySys_Audit,3.13,,
-function,PySys_AuditTuple,3.13,,
-function,PySys_FormatStderr,3.2,,
-function,PySys_FormatStdout,3.2,,
-function,PySys_GetObject,3.2,,
-function,PySys_GetXOptions,3.7,,
-function,PySys_ResetWarnOptions,3.2,,
-function,PySys_SetArgv,3.2,,
-function,PySys_SetArgvEx,3.2,,
-function,PySys_SetObject,3.2,,
-function,PySys_WriteStderr,3.2,,
-function,PySys_WriteStdout,3.2,,
+func,PyStructSequence_GetItem,3.2,,
+func,PyStructSequence_New,3.2,,
+func,PyStructSequence_NewType,3.2,,
+func,PyStructSequence_SetItem,3.2,,
+data,PyStructSequence_UnnamedField,3.11,,
+data,PySuper_Type,3.2,,
+func,PySys_Audit,3.13,,
+func,PySys_AuditTuple,3.13,,
+func,PySys_FormatStderr,3.2,,
+func,PySys_FormatStdout,3.2,,
+func,PySys_GetObject,3.2,,
+func,PySys_GetXOptions,3.7,,
+func,PySys_ResetWarnOptions,3.2,,
+func,PySys_SetArgv,3.2,,
+func,PySys_SetArgvEx,3.2,,
+func,PySys_SetObject,3.2,,
+func,PySys_WriteStderr,3.2,,
+func,PySys_WriteStdout,3.2,,
type,PyThreadState,3.2,,opaque
-function,PyThreadState_Clear,3.2,,
-function,PyThreadState_Delete,3.2,,
-function,PyThreadState_Get,3.2,,
-function,PyThreadState_GetDict,3.2,,
-function,PyThreadState_GetFrame,3.10,,
-function,PyThreadState_GetID,3.10,,
-function,PyThreadState_GetInterpreter,3.10,,
-function,PyThreadState_New,3.2,,
-function,PyThreadState_SetAsyncExc,3.2,,
-function,PyThreadState_Swap,3.2,,
-function,PyThread_GetInfo,3.3,,
-function,PyThread_ReInitTLS,3.2,,
-function,PyThread_acquire_lock,3.2,,
-function,PyThread_acquire_lock_timed,3.2,,
-function,PyThread_allocate_lock,3.2,,
-function,PyThread_create_key,3.2,,
-function,PyThread_delete_key,3.2,,
-function,PyThread_delete_key_value,3.2,,
-function,PyThread_exit_thread,3.2,,
-function,PyThread_free_lock,3.2,,
-function,PyThread_get_key_value,3.2,,
-function,PyThread_get_stacksize,3.2,,
-function,PyThread_get_thread_ident,3.2,,
-function,PyThread_get_thread_native_id,3.2,on platforms with native thread IDs,
-function,PyThread_init_thread,3.2,,
-function,PyThread_release_lock,3.2,,
-function,PyThread_set_key_value,3.2,,
-function,PyThread_set_stacksize,3.2,,
-function,PyThread_start_new_thread,3.2,,
-function,PyThread_tss_alloc,3.7,,
-function,PyThread_tss_create,3.7,,
-function,PyThread_tss_delete,3.7,,
-function,PyThread_tss_free,3.7,,
-function,PyThread_tss_get,3.7,,
-function,PyThread_tss_is_created,3.7,,
-function,PyThread_tss_set,3.7,,
-function,PyTraceBack_Here,3.2,,
-function,PyTraceBack_Print,3.2,,
-var,PyTraceBack_Type,3.2,,
-var,PyTupleIter_Type,3.2,,
-function,PyTuple_GetItem,3.2,,
-function,PyTuple_GetSlice,3.2,,
-function,PyTuple_New,3.2,,
-function,PyTuple_Pack,3.2,,
-function,PyTuple_SetItem,3.2,,
-function,PyTuple_Size,3.2,,
-var,PyTuple_Type,3.2,,
+func,PyThreadState_Clear,3.2,,
+func,PyThreadState_Delete,3.2,,
+func,PyThreadState_Get,3.2,,
+func,PyThreadState_GetDict,3.2,,
+func,PyThreadState_GetFrame,3.10,,
+func,PyThreadState_GetID,3.10,,
+func,PyThreadState_GetInterpreter,3.10,,
+func,PyThreadState_New,3.2,,
+func,PyThreadState_SetAsyncExc,3.2,,
+func,PyThreadState_Swap,3.2,,
+func,PyThread_GetInfo,3.3,,
+func,PyThread_ReInitTLS,3.2,,
+func,PyThread_acquire_lock,3.2,,
+func,PyThread_acquire_lock_timed,3.2,,
+func,PyThread_allocate_lock,3.2,,
+func,PyThread_create_key,3.2,,
+func,PyThread_delete_key,3.2,,
+func,PyThread_delete_key_value,3.2,,
+func,PyThread_exit_thread,3.2,,
+func,PyThread_free_lock,3.2,,
+func,PyThread_get_key_value,3.2,,
+func,PyThread_get_stacksize,3.2,,
+func,PyThread_get_thread_ident,3.2,,
+func,PyThread_get_thread_native_id,3.2,on platforms with native thread IDs,
+func,PyThread_init_thread,3.2,,
+func,PyThread_release_lock,3.2,,
+func,PyThread_set_key_value,3.2,,
+func,PyThread_set_stacksize,3.2,,
+func,PyThread_start_new_thread,3.2,,
+func,PyThread_tss_alloc,3.7,,
+func,PyThread_tss_create,3.7,,
+func,PyThread_tss_delete,3.7,,
+func,PyThread_tss_free,3.7,,
+func,PyThread_tss_get,3.7,,
+func,PyThread_tss_is_created,3.7,,
+func,PyThread_tss_set,3.7,,
+func,PyTraceBack_Here,3.2,,
+func,PyTraceBack_Print,3.2,,
+data,PyTraceBack_Type,3.2,,
+data,PyTupleIter_Type,3.2,,
+func,PyTuple_GetItem,3.2,,
+func,PyTuple_GetSlice,3.2,,
+func,PyTuple_New,3.2,,
+func,PyTuple_Pack,3.2,,
+func,PyTuple_SetItem,3.2,,
+func,PyTuple_Size,3.2,,
+data,PyTuple_Type,3.2,,
type,PyTypeObject,3.2,,opaque
-function,PyType_ClearCache,3.2,,
-function,PyType_FromMetaclass,3.12,,
-function,PyType_FromModuleAndSpec,3.10,,
-function,PyType_FromSpec,3.2,,
-function,PyType_FromSpecWithBases,3.3,,
-function,PyType_GenericAlloc,3.2,,
-function,PyType_GenericNew,3.2,,
-function,PyType_GetFlags,3.2,,
-function,PyType_GetFullyQualifiedName,3.13,,
-function,PyType_GetModule,3.10,,
-function,PyType_GetModuleByDef,3.13,,
-function,PyType_GetModuleName,3.13,,
-function,PyType_GetModuleState,3.10,,
-function,PyType_GetName,3.11,,
-function,PyType_GetQualName,3.11,,
-function,PyType_GetSlot,3.4,,
-function,PyType_GetTypeDataSize,3.12,,
-function,PyType_IsSubtype,3.2,,
-function,PyType_Modified,3.2,,
-function,PyType_Ready,3.2,,
+func,PyType_ClearCache,3.2,,
+func,PyType_FromMetaclass,3.12,,
+func,PyType_FromModuleAndSpec,3.10,,
+func,PyType_FromSpec,3.2,,
+func,PyType_FromSpecWithBases,3.3,,
+func,PyType_GenericAlloc,3.2,,
+func,PyType_GenericNew,3.2,,
+func,PyType_GetFlags,3.2,,
+func,PyType_GetFullyQualifiedName,3.13,,
+func,PyType_GetModule,3.10,,
+func,PyType_GetModuleByDef,3.13,,
+func,PyType_GetModuleName,3.13,,
+func,PyType_GetModuleState,3.10,,
+func,PyType_GetName,3.11,,
+func,PyType_GetQualName,3.11,,
+func,PyType_GetSlot,3.4,,
+func,PyType_GetTypeDataSize,3.12,,
+func,PyType_IsSubtype,3.2,,
+func,PyType_Modified,3.2,,
+func,PyType_Ready,3.2,,
type,PyType_Slot,3.2,,full-abi
type,PyType_Spec,3.2,,full-abi
-var,PyType_Type,3.2,,
-function,PyUnicodeDecodeError_Create,3.2,,
-function,PyUnicodeDecodeError_GetEncoding,3.2,,
-function,PyUnicodeDecodeError_GetEnd,3.2,,
-function,PyUnicodeDecodeError_GetObject,3.2,,
-function,PyUnicodeDecodeError_GetReason,3.2,,
-function,PyUnicodeDecodeError_GetStart,3.2,,
-function,PyUnicodeDecodeError_SetEnd,3.2,,
-function,PyUnicodeDecodeError_SetReason,3.2,,
-function,PyUnicodeDecodeError_SetStart,3.2,,
-function,PyUnicodeEncodeError_GetEncoding,3.2,,
-function,PyUnicodeEncodeError_GetEnd,3.2,,
-function,PyUnicodeEncodeError_GetObject,3.2,,
-function,PyUnicodeEncodeError_GetReason,3.2,,
-function,PyUnicodeEncodeError_GetStart,3.2,,
-function,PyUnicodeEncodeError_SetEnd,3.2,,
-function,PyUnicodeEncodeError_SetReason,3.2,,
-function,PyUnicodeEncodeError_SetStart,3.2,,
-var,PyUnicodeIter_Type,3.2,,
-function,PyUnicodeTranslateError_GetEnd,3.2,,
-function,PyUnicodeTranslateError_GetObject,3.2,,
-function,PyUnicodeTranslateError_GetReason,3.2,,
-function,PyUnicodeTranslateError_GetStart,3.2,,
-function,PyUnicodeTranslateError_SetEnd,3.2,,
-function,PyUnicodeTranslateError_SetReason,3.2,,
-function,PyUnicodeTranslateError_SetStart,3.2,,
-function,PyUnicode_Append,3.2,,
-function,PyUnicode_AppendAndDel,3.2,,
-function,PyUnicode_AsASCIIString,3.2,,
-function,PyUnicode_AsCharmapString,3.2,,
-function,PyUnicode_AsDecodedObject,3.2,,
-function,PyUnicode_AsDecodedUnicode,3.2,,
-function,PyUnicode_AsEncodedObject,3.2,,
-function,PyUnicode_AsEncodedString,3.2,,
-function,PyUnicode_AsEncodedUnicode,3.2,,
-function,PyUnicode_AsLatin1String,3.2,,
-function,PyUnicode_AsMBCSString,3.7,on Windows,
-function,PyUnicode_AsRawUnicodeEscapeString,3.2,,
-function,PyUnicode_AsUCS4,3.7,,
-function,PyUnicode_AsUCS4Copy,3.7,,
-function,PyUnicode_AsUTF16String,3.2,,
-function,PyUnicode_AsUTF32String,3.2,,
-function,PyUnicode_AsUTF8AndSize,3.10,,
-function,PyUnicode_AsUTF8String,3.2,,
-function,PyUnicode_AsUnicodeEscapeString,3.2,,
-function,PyUnicode_AsWideChar,3.2,,
-function,PyUnicode_AsWideCharString,3.7,,
-function,PyUnicode_BuildEncodingMap,3.2,,
-function,PyUnicode_Compare,3.2,,
-function,PyUnicode_CompareWithASCIIString,3.2,,
-function,PyUnicode_Concat,3.2,,
-function,PyUnicode_Contains,3.2,,
-function,PyUnicode_Count,3.2,,
-function,PyUnicode_Decode,3.2,,
-function,PyUnicode_DecodeASCII,3.2,,
-function,PyUnicode_DecodeCharmap,3.2,,
-function,PyUnicode_DecodeCodePageStateful,3.7,on Windows,
-function,PyUnicode_DecodeFSDefault,3.2,,
-function,PyUnicode_DecodeFSDefaultAndSize,3.2,,
-function,PyUnicode_DecodeLatin1,3.2,,
-function,PyUnicode_DecodeLocale,3.7,,
-function,PyUnicode_DecodeLocaleAndSize,3.7,,
-function,PyUnicode_DecodeMBCS,3.7,on Windows,
-function,PyUnicode_DecodeMBCSStateful,3.7,on Windows,
-function,PyUnicode_DecodeRawUnicodeEscape,3.2,,
-function,PyUnicode_DecodeUTF16,3.2,,
-function,PyUnicode_DecodeUTF16Stateful,3.2,,
-function,PyUnicode_DecodeUTF32,3.2,,
-function,PyUnicode_DecodeUTF32Stateful,3.2,,
-function,PyUnicode_DecodeUTF7,3.2,,
-function,PyUnicode_DecodeUTF7Stateful,3.2,,
-function,PyUnicode_DecodeUTF8,3.2,,
-function,PyUnicode_DecodeUTF8Stateful,3.2,,
-function,PyUnicode_DecodeUnicodeEscape,3.2,,
-function,PyUnicode_EncodeCodePage,3.7,on Windows,
-function,PyUnicode_EncodeFSDefault,3.2,,
-function,PyUnicode_EncodeLocale,3.7,,
-function,PyUnicode_EqualToUTF8,3.13,,
-function,PyUnicode_EqualToUTF8AndSize,3.13,,
-function,PyUnicode_FSConverter,3.2,,
-function,PyUnicode_FSDecoder,3.2,,
-function,PyUnicode_Find,3.2,,
-function,PyUnicode_FindChar,3.7,,
-function,PyUnicode_Format,3.2,,
-function,PyUnicode_FromEncodedObject,3.2,,
-function,PyUnicode_FromFormat,3.2,,
-function,PyUnicode_FromFormatV,3.2,,
-function,PyUnicode_FromObject,3.2,,
-function,PyUnicode_FromOrdinal,3.2,,
-function,PyUnicode_FromString,3.2,,
-function,PyUnicode_FromStringAndSize,3.2,,
-function,PyUnicode_FromWideChar,3.2,,
-function,PyUnicode_GetDefaultEncoding,3.2,,
-function,PyUnicode_GetLength,3.7,,
-function,PyUnicode_InternFromString,3.2,,
-function,PyUnicode_InternInPlace,3.2,,
-function,PyUnicode_IsIdentifier,3.2,,
-function,PyUnicode_Join,3.2,,
-function,PyUnicode_Partition,3.2,,
-function,PyUnicode_RPartition,3.2,,
-function,PyUnicode_RSplit,3.2,,
-function,PyUnicode_ReadChar,3.7,,
-function,PyUnicode_Replace,3.2,,
-function,PyUnicode_Resize,3.2,,
-function,PyUnicode_RichCompare,3.2,,
-function,PyUnicode_Split,3.2,,
-function,PyUnicode_Splitlines,3.2,,
-function,PyUnicode_Substring,3.7,,
-function,PyUnicode_Tailmatch,3.2,,
-function,PyUnicode_Translate,3.2,,
-var,PyUnicode_Type,3.2,,
-function,PyUnicode_WriteChar,3.7,,
+data,PyType_Type,3.2,,
+func,PyUnicodeDecodeError_Create,3.2,,
+func,PyUnicodeDecodeError_GetEncoding,3.2,,
+func,PyUnicodeDecodeError_GetEnd,3.2,,
+func,PyUnicodeDecodeError_GetObject,3.2,,
+func,PyUnicodeDecodeError_GetReason,3.2,,
+func,PyUnicodeDecodeError_GetStart,3.2,,
+func,PyUnicodeDecodeError_SetEnd,3.2,,
+func,PyUnicodeDecodeError_SetReason,3.2,,
+func,PyUnicodeDecodeError_SetStart,3.2,,
+func,PyUnicodeEncodeError_GetEncoding,3.2,,
+func,PyUnicodeEncodeError_GetEnd,3.2,,
+func,PyUnicodeEncodeError_GetObject,3.2,,
+func,PyUnicodeEncodeError_GetReason,3.2,,
+func,PyUnicodeEncodeError_GetStart,3.2,,
+func,PyUnicodeEncodeError_SetEnd,3.2,,
+func,PyUnicodeEncodeError_SetReason,3.2,,
+func,PyUnicodeEncodeError_SetStart,3.2,,
+data,PyUnicodeIter_Type,3.2,,
+func,PyUnicodeTranslateError_GetEnd,3.2,,
+func,PyUnicodeTranslateError_GetObject,3.2,,
+func,PyUnicodeTranslateError_GetReason,3.2,,
+func,PyUnicodeTranslateError_GetStart,3.2,,
+func,PyUnicodeTranslateError_SetEnd,3.2,,
+func,PyUnicodeTranslateError_SetReason,3.2,,
+func,PyUnicodeTranslateError_SetStart,3.2,,
+func,PyUnicode_Append,3.2,,
+func,PyUnicode_AppendAndDel,3.2,,
+func,PyUnicode_AsASCIIString,3.2,,
+func,PyUnicode_AsCharmapString,3.2,,
+func,PyUnicode_AsDecodedObject,3.2,,
+func,PyUnicode_AsDecodedUnicode,3.2,,
+func,PyUnicode_AsEncodedObject,3.2,,
+func,PyUnicode_AsEncodedString,3.2,,
+func,PyUnicode_AsEncodedUnicode,3.2,,
+func,PyUnicode_AsLatin1String,3.2,,
+func,PyUnicode_AsMBCSString,3.7,on Windows,
+func,PyUnicode_AsRawUnicodeEscapeString,3.2,,
+func,PyUnicode_AsUCS4,3.7,,
+func,PyUnicode_AsUCS4Copy,3.7,,
+func,PyUnicode_AsUTF16String,3.2,,
+func,PyUnicode_AsUTF32String,3.2,,
+func,PyUnicode_AsUTF8AndSize,3.10,,
+func,PyUnicode_AsUTF8String,3.2,,
+func,PyUnicode_AsUnicodeEscapeString,3.2,,
+func,PyUnicode_AsWideChar,3.2,,
+func,PyUnicode_AsWideCharString,3.7,,
+func,PyUnicode_BuildEncodingMap,3.2,,
+func,PyUnicode_Compare,3.2,,
+func,PyUnicode_CompareWithASCIIString,3.2,,
+func,PyUnicode_Concat,3.2,,
+func,PyUnicode_Contains,3.2,,
+func,PyUnicode_Count,3.2,,
+func,PyUnicode_Decode,3.2,,
+func,PyUnicode_DecodeASCII,3.2,,
+func,PyUnicode_DecodeCharmap,3.2,,
+func,PyUnicode_DecodeCodePageStateful,3.7,on Windows,
+func,PyUnicode_DecodeFSDefault,3.2,,
+func,PyUnicode_DecodeFSDefaultAndSize,3.2,,
+func,PyUnicode_DecodeLatin1,3.2,,
+func,PyUnicode_DecodeLocale,3.7,,
+func,PyUnicode_DecodeLocaleAndSize,3.7,,
+func,PyUnicode_DecodeMBCS,3.7,on Windows,
+func,PyUnicode_DecodeMBCSStateful,3.7,on Windows,
+func,PyUnicode_DecodeRawUnicodeEscape,3.2,,
+func,PyUnicode_DecodeUTF16,3.2,,
+func,PyUnicode_DecodeUTF16Stateful,3.2,,
+func,PyUnicode_DecodeUTF32,3.2,,
+func,PyUnicode_DecodeUTF32Stateful,3.2,,
+func,PyUnicode_DecodeUTF7,3.2,,
+func,PyUnicode_DecodeUTF7Stateful,3.2,,
+func,PyUnicode_DecodeUTF8,3.2,,
+func,PyUnicode_DecodeUTF8Stateful,3.2,,
+func,PyUnicode_DecodeUnicodeEscape,3.2,,
+func,PyUnicode_EncodeCodePage,3.7,on Windows,
+func,PyUnicode_EncodeFSDefault,3.2,,
+func,PyUnicode_EncodeLocale,3.7,,
+func,PyUnicode_EqualToUTF8,3.13,,
+func,PyUnicode_EqualToUTF8AndSize,3.13,,
+func,PyUnicode_FSConverter,3.2,,
+func,PyUnicode_FSDecoder,3.2,,
+func,PyUnicode_Find,3.2,,
+func,PyUnicode_FindChar,3.7,,
+func,PyUnicode_Format,3.2,,
+func,PyUnicode_FromEncodedObject,3.2,,
+func,PyUnicode_FromFormat,3.2,,
+func,PyUnicode_FromFormatV,3.2,,
+func,PyUnicode_FromObject,3.2,,
+func,PyUnicode_FromOrdinal,3.2,,
+func,PyUnicode_FromString,3.2,,
+func,PyUnicode_FromStringAndSize,3.2,,
+func,PyUnicode_FromWideChar,3.2,,
+func,PyUnicode_GetDefaultEncoding,3.2,,
+func,PyUnicode_GetLength,3.7,,
+func,PyUnicode_InternFromString,3.2,,
+func,PyUnicode_InternInPlace,3.2,,
+func,PyUnicode_IsIdentifier,3.2,,
+func,PyUnicode_Join,3.2,,
+func,PyUnicode_Partition,3.2,,
+func,PyUnicode_RPartition,3.2,,
+func,PyUnicode_RSplit,3.2,,
+func,PyUnicode_ReadChar,3.7,,
+func,PyUnicode_Replace,3.2,,
+func,PyUnicode_Resize,3.2,,
+func,PyUnicode_RichCompare,3.2,,
+func,PyUnicode_Split,3.2,,
+func,PyUnicode_Splitlines,3.2,,
+func,PyUnicode_Substring,3.7,,
+func,PyUnicode_Tailmatch,3.2,,
+func,PyUnicode_Translate,3.2,,
+data,PyUnicode_Type,3.2,,
+func,PyUnicode_WriteChar,3.7,,
type,PyVarObject,3.2,,members
member,PyVarObject.ob_base,3.2,,
member,PyVarObject.ob_size,3.2,,
-function,PyVectorcall_Call,3.12,,
-function,PyVectorcall_NARGS,3.12,,
+func,PyVectorcall_Call,3.12,,
+func,PyVectorcall_NARGS,3.12,,
type,PyWeakReference,3.2,,opaque
-function,PyWeakref_GetObject,3.2,,
-function,PyWeakref_GetRef,3.13,,
-function,PyWeakref_NewProxy,3.2,,
-function,PyWeakref_NewRef,3.2,,
-var,PyWrapperDescr_Type,3.2,,
-function,PyWrapper_New,3.2,,
-var,PyZip_Type,3.2,,
-function,Py_AddPendingCall,3.2,,
-function,Py_AtExit,3.2,,
+func,PyWeakref_GetObject,3.2,,
+func,PyWeakref_GetRef,3.13,,
+func,PyWeakref_NewProxy,3.2,,
+func,PyWeakref_NewRef,3.2,,
+data,PyWrapperDescr_Type,3.2,,
+func,PyWrapper_New,3.2,,
+data,PyZip_Type,3.2,,
+macro,Py_AUDIT_READ,3.12,,
+func,Py_AddPendingCall,3.2,,
+func,Py_AtExit,3.2,,
macro,Py_BEGIN_ALLOW_THREADS,3.2,,
macro,Py_BLOCK_THREADS,3.2,,
-function,Py_BuildValue,3.2,,
-function,Py_BytesMain,3.8,,
-function,Py_CompileString,3.2,,
-function,Py_DecRef,3.2,,
-function,Py_DecodeLocale,3.7,,
+func,Py_BuildValue,3.2,,
+func,Py_BytesMain,3.8,,
+func,Py_CompileString,3.2,,
+func,Py_DecRef,3.2,,
+func,Py_DecodeLocale,3.7,,
macro,Py_END_ALLOW_THREADS,3.2,,
-function,Py_EncodeLocale,3.7,,
-function,Py_EndInterpreter,3.2,,
-function,Py_EnterRecursiveCall,3.9,,
-function,Py_Exit,3.2,,
-function,Py_FatalError,3.2,,
-var,Py_FileSystemDefaultEncodeErrors,3.10,,
-var,Py_FileSystemDefaultEncoding,3.2,,
-function,Py_Finalize,3.2,,
-function,Py_FinalizeEx,3.6,,
-function,Py_GenericAlias,3.9,,
-var,Py_GenericAliasType,3.9,,
-function,Py_GetBuildInfo,3.2,,
-function,Py_GetCompiler,3.2,,
-function,Py_GetConstant,3.13,,
-function,Py_GetConstantBorrowed,3.13,,
-function,Py_GetCopyright,3.2,,
-function,Py_GetExecPrefix,3.2,,
-function,Py_GetPath,3.2,,
-function,Py_GetPlatform,3.2,,
-function,Py_GetPrefix,3.2,,
-function,Py_GetProgramFullPath,3.2,,
-function,Py_GetProgramName,3.2,,
-function,Py_GetPythonHome,3.2,,
-function,Py_GetRecursionLimit,3.2,,
-function,Py_GetVersion,3.2,,
-var,Py_HasFileSystemDefaultEncoding,3.2,,
-function,Py_IncRef,3.2,,
-function,Py_Initialize,3.2,,
-function,Py_InitializeEx,3.2,,
-function,Py_Is,3.10,,
-function,Py_IsFalse,3.10,,
-function,Py_IsFinalizing,3.13,,
-function,Py_IsInitialized,3.2,,
-function,Py_IsNone,3.10,,
-function,Py_IsTrue,3.10,,
-function,Py_LeaveRecursiveCall,3.9,,
-function,Py_Main,3.2,,
-function,Py_MakePendingCalls,3.2,,
-function,Py_NewInterpreter,3.2,,
-function,Py_NewRef,3.10,,
-function,Py_ReprEnter,3.2,,
-function,Py_ReprLeave,3.2,,
-function,Py_SetProgramName,3.2,,
-function,Py_SetPythonHome,3.2,,
-function,Py_SetRecursionLimit,3.2,,
+func,Py_EncodeLocale,3.7,,
+func,Py_EndInterpreter,3.2,,
+func,Py_EnterRecursiveCall,3.9,,
+func,Py_Exit,3.2,,
+func,Py_FatalError,3.2,,
+data,Py_FileSystemDefaultEncodeErrors,3.10,,
+data,Py_FileSystemDefaultEncoding,3.2,,
+func,Py_Finalize,3.2,,
+func,Py_FinalizeEx,3.6,,
+func,Py_GenericAlias,3.9,,
+data,Py_GenericAliasType,3.9,,
+func,Py_GetBuildInfo,3.2,,
+func,Py_GetCompiler,3.2,,
+func,Py_GetConstant,3.13,,
+func,Py_GetConstantBorrowed,3.13,,
+func,Py_GetCopyright,3.2,,
+func,Py_GetExecPrefix,3.2,,
+func,Py_GetPath,3.2,,
+func,Py_GetPlatform,3.2,,
+func,Py_GetPrefix,3.2,,
+func,Py_GetProgramFullPath,3.2,,
+func,Py_GetProgramName,3.2,,
+func,Py_GetPythonHome,3.2,,
+func,Py_GetRecursionLimit,3.2,,
+func,Py_GetVersion,3.2,,
+data,Py_HasFileSystemDefaultEncoding,3.2,,
+func,Py_IncRef,3.2,,
+func,Py_Initialize,3.2,,
+func,Py_InitializeEx,3.2,,
+func,Py_Is,3.10,,
+func,Py_IsFalse,3.10,,
+func,Py_IsFinalizing,3.13,,
+func,Py_IsInitialized,3.2,,
+func,Py_IsNone,3.10,,
+func,Py_IsTrue,3.10,,
+func,Py_LeaveRecursiveCall,3.9,,
+func,Py_Main,3.2,,
+func,Py_MakePendingCalls,3.2,,
+func,Py_NewInterpreter,3.2,,
+func,Py_NewRef,3.10,,
+macro,Py_READONLY,3.12,,
+macro,Py_RELATIVE_OFFSET,3.12,,
+func,Py_ReprEnter,3.2,,
+func,Py_ReprLeave,3.2,,
+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_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,,
-var,Py_UTF8Mode,3.8,,
-function,Py_VaBuildValue,3.2,,
-var,Py_Version,3.11,,
-function,Py_XNewRef,3.10,,
+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_create,3.5,,
+macro,Py_mod_exec,3.5,,
+macro,Py_mod_gil,3.13,,
+macro,Py_mod_multiple_interpreters,3.12,,
+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_traverse,3.2,,
type,Py_uintptr_t,3.2,,
type,allocfunc,3.2,,
type,binaryfunc,3.2,,
diff --git a/Doc/deprecations/c-api-pending-removal-in-3.14.rst b/Doc/deprecations/c-api-pending-removal-in-3.14.rst
new file mode 100644
index 000000000000000..d16da66c29abe7e
--- /dev/null
+++ b/Doc/deprecations/c-api-pending-removal-in-3.14.rst
@@ -0,0 +1,72 @@
+Pending Removal in Python 3.14
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* The ``ma_version_tag`` field in :c:type:`PyDictObject` for extension modules
+ (:pep:`699`; :gh:`101193`).
+
+* Creating :c:data:`immutable types ` with mutable
+ bases (:gh:`95388`).
+
+* Functions to configure Python's initialization, deprecated in Python 3.11:
+
+ * :c:func:`!PySys_SetArgvEx()`:
+ Set :c:member:`PyConfig.argv` instead.
+ * :c:func:`!PySys_SetArgv()`:
+ Set :c:member:`PyConfig.argv` instead.
+ * :c:func:`!Py_SetProgramName()`:
+ Set :c:member:`PyConfig.program_name` instead.
+ * :c:func:`!Py_SetPythonHome()`:
+ Set :c:member:`PyConfig.home` instead.
+
+ The :c:func:`Py_InitializeFromConfig` API should be used with
+ :c:type:`PyConfig` instead.
+
+* Global configuration variables:
+
+ * :c:var:`Py_DebugFlag`:
+ Use :c:member:`PyConfig.parser_debug` instead.
+ * :c:var:`Py_VerboseFlag`:
+ Use :c:member:`PyConfig.verbose` instead.
+ * :c:var:`Py_QuietFlag`:
+ Use :c:member:`PyConfig.quiet` instead.
+ * :c:var:`Py_InteractiveFlag`:
+ Use :c:member:`PyConfig.interactive` instead.
+ * :c:var:`Py_InspectFlag`:
+ Use :c:member:`PyConfig.inspect` instead.
+ * :c:var:`Py_OptimizeFlag`:
+ Use :c:member:`PyConfig.optimization_level` instead.
+ * :c:var:`Py_NoSiteFlag`:
+ Use :c:member:`PyConfig.site_import` instead.
+ * :c:var:`Py_BytesWarningFlag`:
+ Use :c:member:`PyConfig.bytes_warning` instead.
+ * :c:var:`Py_FrozenFlag`:
+ Use :c:member:`PyConfig.pathconfig_warnings` instead.
+ * :c:var:`Py_IgnoreEnvironmentFlag`:
+ Use :c:member:`PyConfig.use_environment` instead.
+ * :c:var:`Py_DontWriteBytecodeFlag`:
+ Use :c:member:`PyConfig.write_bytecode` instead.
+ * :c:var:`Py_NoUserSiteDirectory`:
+ Use :c:member:`PyConfig.user_site_directory` instead.
+ * :c:var:`Py_UnbufferedStdioFlag`:
+ Use :c:member:`PyConfig.buffered_stdio` instead.
+ * :c:var:`Py_HashRandomizationFlag`:
+ Use :c:member:`PyConfig.use_hash_seed`
+ and :c:member:`PyConfig.hash_seed` instead.
+ * :c:var:`Py_IsolatedFlag`:
+ Use :c:member:`PyConfig.isolated` instead.
+ * :c:var:`Py_LegacyWindowsFSEncodingFlag`:
+ Use :c:member:`PyPreConfig.legacy_windows_fs_encoding` instead.
+ * :c:var:`Py_LegacyWindowsStdioFlag`:
+ Use :c:member:`PyConfig.legacy_windows_stdio` instead.
+ * :c:var:`!Py_FileSystemDefaultEncoding`:
+ Use :c:member:`PyConfig.filesystem_encoding` instead.
+ * :c:var:`!Py_HasFileSystemDefaultEncoding`:
+ Use :c:member:`PyConfig.filesystem_encoding` instead.
+ * :c:var:`!Py_FileSystemDefaultEncodeErrors`:
+ Use :c:member:`PyConfig.filesystem_errors` instead.
+ * :c:var:`!Py_UTF8Mode`:
+ Use :c:member:`PyPreConfig.utf8_mode` instead.
+ (see :c:func:`Py_PreInitialize`)
+
+ The :c:func:`Py_InitializeFromConfig` API should be used with
+ :c:type:`PyConfig` instead.
diff --git a/Doc/deprecations/c-api-pending-removal-in-3.15.rst b/Doc/deprecations/c-api-pending-removal-in-3.15.rst
new file mode 100644
index 000000000000000..7d46d57dd2f5e6d
--- /dev/null
+++ b/Doc/deprecations/c-api-pending-removal-in-3.15.rst
@@ -0,0 +1,26 @@
+Pending Removal in Python 3.15
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* The :c:func:`PyImport_ImportModuleNoBlock`:
+ Use :c:func:`PyImport_ImportModule` instead.
+* :c:func:`PyWeakref_GetObject` and :c:func:`PyWeakref_GET_OBJECT`:
+ Use :c:func:`PyWeakref_GetRef` instead.
+* :c:type:`Py_UNICODE` type and the :c:macro:`!Py_UNICODE_WIDE` macro:
+ Use :c:type:`wchar_t` instead.
+* Python initialization functions:
+
+ * :c:func:`PySys_ResetWarnOptions`:
+ Clear :data:`sys.warnoptions` and :data:`!warnings.filters` instead.
+ * :c:func:`Py_GetExecPrefix`:
+ Get :data:`sys.base_exec_prefix` and :data:`sys.exec_prefix` instead.
+ * :c:func:`Py_GetPath`:
+ Get :data:`sys.path` instead.
+ * :c:func:`Py_GetPrefix`:
+ Get :data:`sys.base_prefix` and :data:`sys.prefix` instead.
+ * :c:func:`Py_GetProgramFullPath`:
+ Get :data:`sys.executable` instead.
+ * :c:func:`Py_GetProgramName`:
+ Get :data:`sys.executable` instead.
+ * :c:func:`Py_GetPythonHome`:
+ Get :c:member:`PyConfig.home`
+ or the :envvar:`PYTHONHOME` environment variable instead.
diff --git a/Doc/deprecations/c-api-pending-removal-in-3.16.rst b/Doc/deprecations/c-api-pending-removal-in-3.16.rst
new file mode 100644
index 000000000000000..9453f83799c43d7
--- /dev/null
+++ b/Doc/deprecations/c-api-pending-removal-in-3.16.rst
@@ -0,0 +1,4 @@
+Pending removal in Python 3.16
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* The bundled copy of ``libmpdec``.
diff --git a/Doc/deprecations/c-api-pending-removal-in-future.rst b/Doc/deprecations/c-api-pending-removal-in-future.rst
new file mode 100644
index 000000000000000..0c3ae52b87ff74c
--- /dev/null
+++ b/Doc/deprecations/c-api-pending-removal-in-future.rst
@@ -0,0 +1,51 @@
+Pending Removal in Future Versions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following APIs are deprecated and will be removed,
+although there is currently no date scheduled for their removal.
+
+* :c:macro:`Py_TPFLAGS_HAVE_FINALIZE`:
+ Unneeded since Python 3.8.
+* :c:func:`PyErr_Fetch`:
+ Use :c:func:`PyErr_GetRaisedException` instead.
+* :c:func:`PyErr_NormalizeException`:
+ Use :c:func:`PyErr_GetRaisedException` instead.
+* :c:func:`PyErr_Restore`:
+ Use :c:func:`PyErr_SetRaisedException` instead.
+* :c:func:`PyModule_GetFilename`:
+ Use :c:func:`PyModule_GetFilenameObject` instead.
+* :c:func:`PyOS_AfterFork`:
+ Use :c:func:`PyOS_AfterFork_Child` instead.
+* :c:func:`PySlice_GetIndicesEx`:
+ Use :c:func:`PySlice_Unpack` and :c:func:`PySlice_AdjustIndices` instead.
+* :c:func:`!PyUnicode_AsDecodedObject`:
+ Use :c:func:`PyCodec_Decode` instead.
+* :c:func:`!PyUnicode_AsDecodedUnicode`:
+ Use :c:func:`PyCodec_Decode` instead.
+* :c:func:`!PyUnicode_AsEncodedObject`:
+ Use :c:func:`PyCodec_Encode` instead.
+* :c:func:`!PyUnicode_AsEncodedUnicode`:
+ Use :c:func:`PyCodec_Encode` instead.
+* :c:func:`PyUnicode_READY`:
+ Unneeded since Python 3.12
+* :c:func:`!PyErr_Display`:
+ Use :c:func:`PyErr_DisplayException` instead.
+* :c:func:`!_PyErr_ChainExceptions`:
+ Use :c:func:`!_PyErr_ChainExceptions1` instead.
+* :c:member:`!PyBytesObject.ob_shash` member:
+ call :c:func:`PyObject_Hash` instead.
+* :c:member:`!PyDictObject.ma_version_tag` member.
+* Thread Local Storage (TLS) API:
+
+ * :c:func:`PyThread_create_key`:
+ Use :c:func:`PyThread_tss_alloc` instead.
+ * :c:func:`PyThread_delete_key`:
+ Use :c:func:`PyThread_tss_free` instead.
+ * :c:func:`PyThread_set_key_value`:
+ Use :c:func:`PyThread_tss_set` instead.
+ * :c:func:`PyThread_get_key_value`:
+ Use :c:func:`PyThread_tss_get` instead.
+ * :c:func:`PyThread_delete_key_value`:
+ Use :c:func:`PyThread_tss_delete` instead.
+ * :c:func:`PyThread_ReInitTLS`:
+ Unneeded since Python 3.7.
diff --git a/Doc/deprecations/index.rst b/Doc/deprecations/index.rst
new file mode 100644
index 000000000000000..f004724fac08ba0
--- /dev/null
+++ b/Doc/deprecations/index.rst
@@ -0,0 +1,23 @@
+Deprecations
+============
+
+.. include:: pending-removal-in-3.14.rst
+
+.. include:: pending-removal-in-3.15.rst
+
+.. include:: pending-removal-in-3.16.rst
+
+.. include:: pending-removal-in-3.17.rst
+
+.. include:: pending-removal-in-3.18.rst
+
+.. include:: pending-removal-in-future.rst
+
+C API Deprecations
+------------------
+
+.. include:: c-api-pending-removal-in-3.14.rst
+
+.. include:: c-api-pending-removal-in-3.15.rst
+
+.. include:: c-api-pending-removal-in-future.rst
diff --git a/Doc/deprecations/pending-removal-in-3.13.rst b/Doc/deprecations/pending-removal-in-3.13.rst
new file mode 100644
index 000000000000000..0505e0d1e5fe8c4
--- /dev/null
+++ b/Doc/deprecations/pending-removal-in-3.13.rst
@@ -0,0 +1,40 @@
+Pending Removal in Python 3.13
+------------------------------
+
+Modules (see :pep:`594`):
+
+* :mod:`!aifc`
+* :mod:`!audioop`
+* :mod:`!cgi`
+* :mod:`!cgitb`
+* :mod:`!chunk`
+* :mod:`!crypt`
+* :mod:`!imghdr`
+* :mod:`!mailcap`
+* :mod:`!msilib`
+* :mod:`!nis`
+* :mod:`!nntplib`
+* :mod:`!ossaudiodev`
+* :mod:`!pipes`
+* :mod:`!sndhdr`
+* :mod:`!spwd`
+* :mod:`!sunau`
+* :mod:`!telnetlib`
+* :mod:`!uu`
+* :mod:`!xdrlib`
+
+Other modules:
+
+* :mod:`!lib2to3`, and the :program:`2to3` program (:gh:`84540`)
+
+APIs:
+
+* :class:`!configparser.LegacyInterpolation` (:gh:`90765`)
+* ``locale.resetlocale()`` (:gh:`90817`)
+* :meth:`!turtle.RawTurtle.settiltangle` (:gh:`50096`)
+* :func:`!unittest.findTestCases` (:gh:`50096`)
+* :func:`!unittest.getTestCaseNames` (:gh:`50096`)
+* :func:`!unittest.makeSuite` (:gh:`50096`)
+* :meth:`!unittest.TestProgram.usageExit` (:gh:`67048`)
+* :class:`!webbrowser.MacOSX` (:gh:`86421`)
+* :class:`classmethod` descriptor chaining (:gh:`89519`)
diff --git a/Doc/deprecations/pending-removal-in-3.14.rst b/Doc/deprecations/pending-removal-in-3.14.rst
new file mode 100644
index 000000000000000..e8554a78c608f06
--- /dev/null
+++ b/Doc/deprecations/pending-removal-in-3.14.rst
@@ -0,0 +1,100 @@
+Pending Removal in Python 3.14
+------------------------------
+
+* :mod:`argparse`: The *type*, *choices*, and *metavar* parameters
+ of :class:`!argparse.BooleanOptionalAction` are deprecated
+ and will be removed in 3.14.
+ (Contributed by Nikita Sobolev in :gh:`92248`.)
+
+* :mod:`ast`: The following features have been deprecated in documentation
+ since Python 3.8, now cause a :exc:`DeprecationWarning` to be emitted at
+ runtime when they are accessed or used, and will be removed in Python 3.14:
+
+ * :class:`!ast.Num`
+ * :class:`!ast.Str`
+ * :class:`!ast.Bytes`
+ * :class:`!ast.NameConstant`
+ * :class:`!ast.Ellipsis`
+
+ Use :class:`ast.Constant` instead.
+ (Contributed by Serhiy Storchaka in :gh:`90953`.)
+
+* :mod:`asyncio`:
+
+ * The child watcher classes :class:`~asyncio.MultiLoopChildWatcher`,
+ :class:`~asyncio.FastChildWatcher`, :class:`~asyncio.AbstractChildWatcher`
+ and :class:`~asyncio.SafeChildWatcher` are deprecated and
+ will be removed in Python 3.14.
+ (Contributed by Kumar Aditya in :gh:`94597`.)
+
+ * :func:`asyncio.set_child_watcher`, :func:`asyncio.get_child_watcher`,
+ :meth:`asyncio.AbstractEventLoopPolicy.set_child_watcher` and
+ :meth:`asyncio.AbstractEventLoopPolicy.get_child_watcher` are deprecated
+ and will be removed in Python 3.14.
+ (Contributed by Kumar Aditya in :gh:`94597`.)
+
+ * The :meth:`~asyncio.get_event_loop` method of the
+ default event loop policy now emits a :exc:`DeprecationWarning` if there
+ is no current event loop set and it decides to create one.
+ (Contributed by Serhiy Storchaka and Guido van Rossum in :gh:`100160`.)
+
+* :mod:`builtins`: ``bool(NotImplemented)`` now emits a :exc:`DeprecationWarning`
+ and will raise a :exc:`TypeError` in Python 3.14.
+ (Contributed by Jelle Zijlstra in :gh:`118767`.)
+
+* :mod:`email`: Deprecated the *isdst* parameter in :func:`email.utils.localtime`.
+ (Contributed by Alan Williams in :gh:`72346`.)
+
+* :mod:`importlib.abc` deprecated classes:
+
+ * :class:`!importlib.abc.ResourceReader`
+ * :class:`!importlib.abc.Traversable`
+ * :class:`!importlib.abc.TraversableResources`
+
+ Use :mod:`importlib.resources.abc` classes instead:
+
+ * :class:`importlib.resources.abc.Traversable`
+ * :class:`importlib.resources.abc.TraversableResources`
+
+ (Contributed by Jason R. Coombs and Hugo van Kemenade in :gh:`93963`.)
+
+* :mod:`itertools` had undocumented, inefficient, historically buggy,
+ and inconsistent support for copy, deepcopy, and pickle operations.
+ This will be removed in 3.14 for a significant reduction in code
+ volume and maintenance burden.
+ (Contributed by Raymond Hettinger in :gh:`101588`.)
+
+* :mod:`multiprocessing`: The default start method will change to a safer one on
+ Linux, BSDs, and other non-macOS POSIX platforms where ``'fork'`` is currently
+ the default (:gh:`84559`). Adding a runtime warning about this was deemed too
+ disruptive as the majority of code is not expected to care. Use the
+ :func:`~multiprocessing.get_context` or
+ :func:`~multiprocessing.set_start_method` APIs to explicitly specify when
+ your code *requires* ``'fork'``. See :ref:`multiprocessing-start-methods`.
+
+* :mod:`pathlib`: :meth:`~pathlib.PurePath.is_relative_to` and
+ :meth:`~pathlib.PurePath.relative_to`: passing additional arguments is
+ deprecated.
+
+* :mod:`pkgutil`: :func:`~pkgutil.find_loader` and :func:`~pkgutil.get_loader`
+ now raise :exc:`DeprecationWarning`;
+ use :func:`importlib.util.find_spec` instead.
+ (Contributed by Nikita Sobolev in :gh:`97850`.)
+
+* :mod:`pty`:
+
+ * ``master_open()``: use :func:`pty.openpty`.
+ * ``slave_open()``: use :func:`pty.openpty`.
+
+* :mod:`sqlite3`:
+
+ * :data:`~sqlite3.version` and :data:`~sqlite3.version_info`.
+
+ * :meth:`~sqlite3.Cursor.execute` and :meth:`~sqlite3.Cursor.executemany`
+ if :ref:`named placeholders ` are used and
+ *parameters* is a sequence instead of a :class:`dict`.
+
+* :mod:`urllib`:
+ :class:`!urllib.parse.Quoter` is deprecated: it was not intended to be a
+ public API.
+ (Contributed by Gregory P. Smith in :gh:`88168`.)
diff --git a/Doc/deprecations/pending-removal-in-3.15.rst b/Doc/deprecations/pending-removal-in-3.15.rst
new file mode 100644
index 000000000000000..eb3dc4f175d3c8c
--- /dev/null
+++ b/Doc/deprecations/pending-removal-in-3.15.rst
@@ -0,0 +1,95 @@
+Pending Removal in Python 3.15
+------------------------------
+
+* The import system:
+
+ * Setting :attr:`~module.__cached__` on a module while
+ failing to set :attr:`__spec__.cached `
+ 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
+ failing to set :attr:`__spec__.parent `
+ is deprecated. In Python 3.15, :attr:`!__package__` will cease to be set or
+ take into consideration by the import system or standard library. (:gh:`97879`)
+
+* :mod:`ctypes`:
+
+ * The undocumented :func:`!ctypes.SetPointerType` function
+ has been deprecated since Python 3.13.
+
+* :mod:`http.server`:
+
+ * The obsolete and rarely used :class:`~http.server.CGIHTTPRequestHandler`
+ has been deprecated since Python 3.13.
+ No direct replacement exists.
+ *Anything* is better than CGI to interface
+ a web server with a request handler.
+
+ * The :option:`!--cgi` flag to the :program:`python -m http.server`
+ command-line interface has been deprecated since Python 3.13.
+
+* :mod:`importlib`:
+
+ * ``load_module()`` method: use ``exec_module()`` instead.
+
+* :mod:`pathlib`:
+
+ * :meth:`.PurePath.is_reserved`
+ has been deprecated since Python 3.13.
+ Use :func:`os.path.isreserved` to detect reserved paths on Windows.
+
+* :mod:`platform`:
+
+ * :func:`~platform.java_ver` has been deprecated since Python 3.13.
+ This function is only useful for Jython support, has a confusing API,
+ and is largely untested.
+
+* :mod:`sysconfig`:
+
+ * The *check_home* argument of :func:`sysconfig.is_python_build` has been
+ deprecated since Python 3.12.
+
+* :mod:`threading`:
+
+ * :func:`~threading.RLock` will take no arguments in Python 3.15.
+ Passing any arguments has been deprecated since Python 3.14,
+ as the Python version does not permit any arguments,
+ but the C version allows any number of positional or keyword arguments,
+ ignoring every argument.
+
+* :mod:`types`:
+
+ * :class:`types.CodeType`: Accessing :attr:`~codeobject.co_lnotab` was
+ deprecated in :pep:`626`
+ since 3.10 and was planned to be removed in 3.12,
+ but it only got a proper :exc:`DeprecationWarning` in 3.12.
+ May be removed in 3.15.
+ (Contributed by Nikita Sobolev in :gh:`101866`.)
+
+* :mod:`typing`:
+
+ * The undocumented keyword argument syntax for creating
+ :class:`~typing.NamedTuple` classes
+ (e.g. ``Point = NamedTuple("Point", x=int, y=int)``)
+ has been deprecated since Python 3.13.
+ Use the class-based syntax or the functional syntax instead.
+
+ * When using the functional syntax of :class:`~typing.TypedDict`\s, failing
+ to pass a value to the *fields* parameter (``TD = TypedDict("TD")``) or
+ passing ``None`` (``TD = TypedDict("TD", None)``) has been deprecated
+ since Python 3.13.
+ Use ``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``
+ to create a TypedDict with zero field.
+
+ * The :deco:`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.
+
+* :mod:`wave`:
+
+ * The :meth:`~wave.Wave_read.getmark`, :meth:`!setmark`,
+ and :meth:`~wave.Wave_read.getmarkers` methods of
+ the :class:`~wave.Wave_read` and :class:`~wave.Wave_write` classes
+ have been deprecated since Python 3.13.
diff --git a/Doc/deprecations/pending-removal-in-3.16.rst b/Doc/deprecations/pending-removal-in-3.16.rst
new file mode 100644
index 000000000000000..6f6954b783a1aeb
--- /dev/null
+++ b/Doc/deprecations/pending-removal-in-3.16.rst
@@ -0,0 +1,56 @@
+Pending removal in Python 3.16
+------------------------------
+
+* The import system:
+
+ * Setting :attr:`~module.__loader__` on a module while
+ failing to set :attr:`__spec__.loader `
+ is deprecated. In Python 3.16, :attr:`!__loader__` will cease to be set or
+ taken into consideration by the import system or the standard library.
+
+* :mod:`array`:
+
+ * The ``'u'`` format code (:c:type:`wchar_t`)
+ has been deprecated in documentation since Python 3.3
+ and at runtime since Python 3.13.
+ Use the ``'w'`` format code (:c:type:`Py_UCS4`)
+ for Unicode characters instead.
+
+* :mod:`asyncio`:
+
+ * :func:`!asyncio.iscoroutinefunction` is deprecated
+ and will be removed in Python 3.16,
+ use :func:`inspect.iscoroutinefunction` instead.
+ (Contributed by Jiahao Li and Kumar Aditya in :gh:`122875`.)
+
+* :mod:`builtins`:
+
+ * Bitwise inversion on boolean types, ``~True`` or ``~False``
+ has been deprecated since Python 3.12,
+ as it produces surprising and unintuitive results (``-2`` and ``-1``).
+ Use ``not x`` instead for the logical negation of a Boolean.
+ In the rare case that you need the bitwise inversion of
+ the underlying integer, convert to ``int`` explicitly (``~int(x)``).
+
+* :mod:`shutil`:
+
+ * The :class:`!ExecError` exception
+ has been deprecated since Python 3.14.
+ It has not been used by any function in :mod:`!shutil` since Python 3.4,
+ and is now an alias of :exc:`RuntimeError`.
+
+* :mod:`symtable`:
+
+ * The :meth:`Class.get_methods ` method
+ has been deprecated since Python 3.14.
+
+* :mod:`sys`:
+
+ * The :func:`~sys._enablelegacywindowsfsencoding` function
+ has been deprecated since Python 3.13.
+ Use the :envvar:`PYTHONLEGACYWINDOWSFSENCODING` environment variable instead.
+
+* :mod:`tarfile`:
+
+ * The undocumented and unused :attr:`!TarFile.tarfile` attribute
+ has been deprecated since Python 3.13.
diff --git a/Doc/deprecations/pending-removal-in-3.17.rst b/Doc/deprecations/pending-removal-in-3.17.rst
new file mode 100644
index 000000000000000..0a1c2f08cab3bd7
--- /dev/null
+++ b/Doc/deprecations/pending-removal-in-3.17.rst
@@ -0,0 +1,51 @@
+Pending removal in Python 3.17
+------------------------------
+
+* :mod:`collections.abc`:
+
+ - :class:`collections.abc.ByteString` is scheduled for removal in Python 3.17.
+
+ Use ``isinstance(obj, collections.abc.Buffer)`` to test if ``obj``
+ implements the :ref:`buffer protocol ` at runtime. For use
+ in type annotations, either use :class:`~collections.abc.Buffer` or a union
+ that explicitly specifies the types your code supports (e.g.,
+ ``bytes | bytearray | memoryview``).
+
+ :class:`!ByteString` was originally intended to be an abstract class that
+ would serve as a supertype of both :class:`bytes` and :class:`bytearray`.
+ However, since the ABC never had any methods, knowing that an object was an
+ instance of :class:`!ByteString` never actually told you anything useful
+ about the object. Other common buffer types such as :class:`memoryview`
+ were also never understood as subtypes of :class:`!ByteString` (either at
+ runtime or by static type checkers).
+
+ See :pep:`PEP 688 <688#current-options>` for more details.
+ (Contributed by Shantanu Jain in :gh:`91896`.)
+
+
+* :mod:`typing`:
+
+ - Before Python 3.14, old-style unions were implemented using the private class
+ ``typing._UnionGenericAlias``. This class is no longer needed for the implementation,
+ but it has been retained for backward compatibility, with removal scheduled for Python
+ 3.17. Users should use documented introspection helpers like :func:`typing.get_origin`
+ and :func:`typing.get_args` instead of relying on private implementation details.
+ - :class:`typing.ByteString`, deprecated since Python 3.9, is scheduled for removal in
+ Python 3.17.
+
+ Use ``isinstance(obj, collections.abc.Buffer)`` to test if ``obj``
+ implements the :ref:`buffer protocol ` at runtime. For use
+ in type annotations, either use :class:`~collections.abc.Buffer` or a union
+ that explicitly specifies the types your code supports (e.g.,
+ ``bytes | bytearray | memoryview``).
+
+ :class:`!ByteString` was originally intended to be an abstract class that
+ would serve as a supertype of both :class:`bytes` and :class:`bytearray`.
+ However, since the ABC never had any methods, knowing that an object was an
+ instance of :class:`!ByteString` never actually told you anything useful
+ about the object. Other common buffer types such as :class:`memoryview`
+ were also never understood as subtypes of :class:`!ByteString` (either at
+ runtime or by static type checkers).
+
+ See :pep:`PEP 688 <688#current-options>` for more details.
+ (Contributed by Shantanu Jain in :gh:`91896`.)
diff --git a/Doc/deprecations/pending-removal-in-3.18.rst b/Doc/deprecations/pending-removal-in-3.18.rst
new file mode 100644
index 000000000000000..3e7992194784240
--- /dev/null
+++ b/Doc/deprecations/pending-removal-in-3.18.rst
@@ -0,0 +1,9 @@
+Pending removal in Python 3.18
+------------------------------
+
+* :mod:`decimal`:
+
+ * The non-standard and undocumented :class:`~decimal.Decimal` format
+ specifier ``'N'``, which is only supported in the :mod:`!decimal` module's
+ C implementation, has been deprecated since Python 3.13.
+ (Contributed by Serhiy Storchaka in :gh:`89902`.)
diff --git a/Doc/deprecations/pending-removal-in-future.rst b/Doc/deprecations/pending-removal-in-future.rst
new file mode 100644
index 000000000000000..20707c644e2ac11
--- /dev/null
+++ b/Doc/deprecations/pending-removal-in-future.rst
@@ -0,0 +1,148 @@
+Pending Removal in Future Versions
+----------------------------------
+
+The following APIs will be removed in the future,
+although there is currently no date scheduled for their removal.
+
+* :mod:`argparse`: Nesting argument groups and nesting mutually exclusive
+ groups are deprecated.
+
+* :mod:`builtins`:
+
+ * Generators: ``throw(type, exc, tb)`` and ``athrow(type, exc, tb)``
+ signature is deprecated: use ``throw(exc)`` and ``athrow(exc)`` instead,
+ the single argument signature.
+ * Currently Python accepts numeric literals immediately followed by keywords,
+ for example ``0in x``, ``1or x``, ``0if 1else 2``. It allows confusing and
+ ambiguous expressions like ``[0x1for x in y]`` (which can be interpreted as
+ ``[0x1 for x in y]`` or ``[0x1f or x in y]``). A syntax warning is raised
+ if the numeric literal is immediately followed by one of keywords
+ :keyword:`and`, :keyword:`else`, :keyword:`for`, :keyword:`if`,
+ :keyword:`in`, :keyword:`is` and :keyword:`or`. In a future release it
+ will be changed to a syntax error. (:gh:`87999`)
+ * Support for ``__index__()`` and ``__int__()`` method returning non-int type:
+ these methods will be required to return an instance of a strict subclass of
+ :class:`int`.
+ * Support for ``__float__()`` method returning a strict subclass of
+ :class:`float`: these methods will be required to return an instance of
+ :class:`float`.
+ * Support for ``__complex__()`` method returning a strict subclass of
+ :class:`complex`: these methods will be required to return an instance of
+ :class:`complex`.
+ * Delegation of ``int()`` to ``__trunc__()`` method.
+ * Passing a complex number as the *real* or *imag* argument in the
+ :func:`complex` constructor is now deprecated; it should only be passed
+ as a single positional argument.
+ (Contributed by Serhiy Storchaka in :gh:`109218`.)
+
+* :mod:`calendar`: ``calendar.January`` and ``calendar.February`` constants are
+ deprecated and replaced by :data:`calendar.JANUARY` and
+ :data:`calendar.FEBRUARY`.
+ (Contributed by Prince Roshan in :gh:`103636`.)
+
+* :attr:`codeobject.co_lnotab`: use the :meth:`codeobject.co_lines` method
+ instead.
+
+* :mod:`datetime`:
+
+ * :meth:`~datetime.datetime.utcnow`:
+ use ``datetime.datetime.now(tz=datetime.UTC)``.
+ * :meth:`~datetime.datetime.utcfromtimestamp`:
+ use ``datetime.datetime.fromtimestamp(timestamp, tz=datetime.UTC)``.
+
+* :mod:`gettext`: Plural value must be an integer.
+
+* :mod:`importlib`:
+
+ * :func:`~importlib.util.cache_from_source` *debug_override* parameter is
+ deprecated: use the *optimization* parameter instead.
+
+* :mod:`importlib.metadata`:
+
+ * ``EntryPoints`` tuple interface.
+ * Implicit ``None`` on return values.
+
+* :mod:`logging`: the ``warn()`` method has been deprecated
+ since Python 3.3, use :meth:`~logging.warning` instead.
+
+* :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 multi-threaded process.
+
+* :class:`!pydoc.ErrorDuringImport`: A tuple value for *exc_info* parameter is
+ deprecated, use an exception instance.
+
+* :mod:`re`: More strict rules are now applied for numerical group references
+ and group names in regular expressions. Only sequence of ASCII digits is now
+ accepted as a numerical reference. The group name in bytes patterns and
+ replacement strings can now only contain ASCII letters and digits and
+ underscore.
+ (Contributed by Serhiy Storchaka in :gh:`91760`.)
+
+* :mod:`!sre_compile`, :mod:`!sre_constants` and :mod:`!sre_parse` modules.
+
+* :mod:`shutil`: :func:`~shutil.rmtree`'s *onerror* parameter is deprecated in
+ Python 3.12; use the *onexc* parameter instead.
+
+* :mod:`ssl` options and protocols:
+
+ * :class:`ssl.SSLContext` without protocol argument is deprecated.
+ * :class:`ssl.SSLContext`: :meth:`~ssl.SSLContext.set_npn_protocols` and
+ :meth:`!selected_npn_protocol` are deprecated: use ALPN
+ instead.
+ * ``ssl.OP_NO_SSL*`` options
+ * ``ssl.OP_NO_TLS*`` options
+ * ``ssl.PROTOCOL_SSLv3``
+ * ``ssl.PROTOCOL_TLS``
+ * ``ssl.PROTOCOL_TLSv1``
+ * ``ssl.PROTOCOL_TLSv1_1``
+ * ``ssl.PROTOCOL_TLSv1_2``
+ * ``ssl.TLSVersion.SSLv3``
+ * ``ssl.TLSVersion.TLSv1``
+ * ``ssl.TLSVersion.TLSv1_1``
+
+* :mod:`threading` methods:
+
+ * :meth:`!threading.Condition.notifyAll`: use :meth:`~threading.Condition.notify_all`.
+ * :meth:`!threading.Event.isSet`: use :meth:`~threading.Event.is_set`.
+ * :meth:`!threading.Thread.isDaemon`, :meth:`threading.Thread.setDaemon`:
+ use :attr:`threading.Thread.daemon` attribute.
+ * :meth:`!threading.Thread.getName`, :meth:`threading.Thread.setName`:
+ use :attr:`threading.Thread.name` attribute.
+ * :meth:`!threading.currentThread`: use :meth:`threading.current_thread`.
+ * :meth:`!threading.activeCount`: use :meth:`threading.active_count`.
+
+* :class:`typing.Text` (:gh:`92332`).
+
+* :class:`unittest.IsolatedAsyncioTestCase`: it is deprecated to return a value
+ that is not ``None`` from a test case.
+
+* :mod:`urllib.parse` deprecated functions: :func:`~urllib.parse.urlparse` instead
+
+ * ``splitattr()``
+ * ``splithost()``
+ * ``splitnport()``
+ * ``splitpasswd()``
+ * ``splitport()``
+ * ``splitquery()``
+ * ``splittag()``
+ * ``splittype()``
+ * ``splituser()``
+ * ``splitvalue()``
+ * ``to_bytes()``
+
+* :mod:`urllib.request`: :class:`~urllib.request.URLopener` and
+ :class:`~urllib.request.FancyURLopener` style of invoking requests is
+ deprecated. Use newer :func:`~urllib.request.urlopen` functions and methods.
+
+* :mod:`wsgiref`: ``SimpleHandler.stdout.write()`` should not do partial
+ writes.
+
+* :mod:`xml.etree.ElementTree`: Testing the truth value of an
+ :class:`~xml.etree.ElementTree.Element` is deprecated. In a future release it
+ will always return ``True``. Prefer explicit ``len(elem)`` or
+ ``elem is not None`` tests instead.
+
+* :meth:`zipimport.zipimporter.load_module` is deprecated:
+ use :meth:`~zipimport.zipimporter.exec_module` instead.
diff --git a/Doc/extending/building.rst b/Doc/extending/building.rst
index ddde567f6f3efa5..a58eb40d431c594 100644
--- a/Doc/extending/building.rst
+++ b/Doc/extending/building.rst
@@ -23,10 +23,10 @@ instance. See :ref:`initializing-modules` for details.
.. highlight:: python
For modules with ASCII-only names, the function must be named
-``PyInit_``, with ```` replaced by the name of the
-module. When using :ref:`multi-phase-initialization`, non-ASCII module names
+:samp:`PyInit_{}`, with ```` 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
-``PyInitU_``, with ```` encoded using Python's
+:samp:`PyInitU_{}`, with ```` encoded using Python's
*punycode* encoding with hyphens replaced by underscores. In Python::
def initfunc_name(name):
diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst
index 20397dc5add5db6..cb41889437c8b0d 100644
--- a/Doc/extending/embedding.rst
+++ b/Doc/extending/embedding.rst
@@ -196,8 +196,8 @@ interesting part with respect to embedding Python starts with ::
After initializing the interpreter, the script is loaded using
:c:func:`PyImport_Import`. This routine needs a Python string as its argument,
-which is constructed using the :c:func:`PyUnicode_FromString` data conversion
-routine. ::
+which is constructed using the :c:func:`PyUnicode_DecodeFSDefault` data
+conversion routine. ::
pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */
@@ -245,21 +245,23 @@ Python extension. For example::
return PyLong_FromLong(numargs);
}
- static PyMethodDef EmbMethods[] = {
+ static PyMethodDef emb_module_methods[] = {
{"numargs", emb_numargs, METH_VARARGS,
"Return the number of arguments received by the process."},
{NULL, NULL, 0, NULL}
};
- static PyModuleDef EmbModule = {
- PyModuleDef_HEAD_INIT, "emb", NULL, -1, EmbMethods,
- NULL, NULL, NULL, NULL
+ static struct PyModuleDef emb_module = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "emb",
+ .m_size = 0,
+ .m_methods = emb_module_methods,
};
static PyObject*
PyInit_emb(void)
{
- return PyModule_Create(&EmbModule);
+ return PyModuleDef_Init(&emb_module);
}
Insert the above code just above the :c:func:`main` function. Also, insert the
diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst
index b70e1b1fe57e67c..6518e20cafbc9e7 100644
--- a/Doc/extending/extending.rst
+++ b/Doc/extending/extending.rst
@@ -75,12 +75,37 @@ the module and a copyright notice if you like).
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. For convenience, and
-since they are used extensively by the Python interpreter, ``"Python.h"``
-includes a few standard header files: ````, ````,
-````, and ````. If the latter header file does not exist on
-your system, it declares the functions :c:func:`malloc`, :c:func:`free` and
-:c:func:`realloc` directly.
+``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:
+
+ * ````
+ * ```` (on Windows)
+ * ````
+ * ````
+ * ````
+ * ````
+ * ````
+ * ```` (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:
+
+ * ````
+ * ```` (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:
+
+ * ````
+ * ````
+ * ````
+ * ````
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
@@ -203,31 +228,57 @@ function usually raises :c:data:`PyExc_TypeError`. If you have an argument whos
value must be in a particular range or must satisfy other conditions,
:c:data:`PyExc_ValueError` is appropriate.
-You can also define a new exception that is unique to your module. For this, you
-usually declare a static object variable at the beginning of your file::
+You can also define a new exception that is unique to your module.
+The simplest way to do this is to declare a static global object variable at
+the beginning of the file::
- static PyObject *SpamError;
+ static PyObject *SpamError = NULL;
-and initialize it in your module's initialization function (:c:func:`!PyInit_spam`)
-with an exception object::
+and initialize it by calling :c:func:`PyErr_NewException` in the module's
+:c:data:`Py_mod_exec` function (:c:func:`!spam_module_exec`)::
- PyMODINIT_FUNC
- PyInit_spam(void)
- {
- PyObject *m;
+ SpamError = PyErr_NewException("spam.error", NULL, NULL);
- m = PyModule_Create(&spammodule);
- if (m == NULL)
- return NULL;
+Since :c:data:`!SpamError` is a global variable, it will be overwritten every time
+the module is reinitialized, when the :c:data:`Py_mod_exec` function is called.
+
+For now, let's avoid the issue: we will block repeated initialization by raising an
+:py:exc:`ImportError`::
+ static PyObject *SpamError = NULL;
+
+ static int
+ spam_module_exec(PyObject *m)
+ {
+ if (SpamError != NULL) {
+ PyErr_SetString(PyExc_ImportError,
+ "cannot initialize spam module more than once");
+ return -1;
+ }
SpamError = PyErr_NewException("spam.error", NULL, NULL);
- if (PyModule_AddObjectRef(m, "error", SpamError) < 0) {
- Py_CLEAR(SpamError);
- Py_DECREF(m);
- return NULL;
+ if (PyModule_AddObjectRef(m, "SpamError", SpamError) < 0) {
+ return -1;
}
- return m;
+ return 0;
+ }
+
+ static PyModuleDef_Slot spam_module_slots[] = {
+ {Py_mod_exec, spam_module_exec},
+ {0, NULL}
+ };
+
+ static struct PyModuleDef spam_module = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "spam",
+ .m_size = 0, // non-negative
+ .m_slots = spam_module_slots,
+ };
+
+ PyMODINIT_FUNC
+ PyInit_spam(void)
+ {
+ return PyModuleDef_Init(&spam_module);
}
Note that the Python name for the exception object is :exc:`!spam.error`. The
@@ -242,6 +293,11 @@ needed to ensure that it will not be discarded, causing :c:data:`!SpamError` to
become a dangling pointer. Should it become a dangling pointer, C code which
raises the exception could cause a core dump or other unintended side effects.
+For now, the :c:func:`Py_DECREF` call to remove this reference is missing.
+Even when the Python interpreter shuts down, the global :c:data:`!SpamError`
+variable will not be garbage-collected. It will "leak".
+We did, however, ensure that this will happen at most once per process.
+
We discuss the use of :c:macro:`PyMODINIT_FUNC` as a function return type later in this
sample.
@@ -318,7 +374,7 @@ 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 SpamMethods[] = {
+ static PyMethodDef spam_methods[] = {
...
{"system", spam_system, METH_VARARGS,
"Execute a shell command."},
@@ -343,13 +399,10 @@ function.
The method table must be referenced in the module definition structure::
- static struct PyModuleDef spammodule = {
- PyModuleDef_HEAD_INIT,
- "spam", /* name of module */
- spam_doc, /* module documentation, may be NULL */
- -1, /* size of per-interpreter state of the module,
- or -1 if the module keeps state in global variables. */
- SpamMethods
+ static struct PyModuleDef spam_module = {
+ ...
+ .m_methods = spam_methods,
+ ...
};
This structure, in turn, must be passed to the interpreter in the module's
@@ -360,23 +413,17 @@ only non-\ ``static`` item defined in the module file::
PyMODINIT_FUNC
PyInit_spam(void)
{
- return PyModule_Create(&spammodule);
+ 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"``.
-When the Python program imports module :mod:`!spam` for the first time,
-:c:func:`!PyInit_spam` is called. (See below for comments about embedding Python.)
-It calls :c:func:`PyModule_Create`, which returns a module object, and
-inserts built-in function objects into the newly created module based upon the
-table (an array of :c:type:`PyMethodDef` structures) found in the module definition.
-:c:func:`PyModule_Create` returns a pointer to the module object
-that it creates. It may abort with a fatal error for
-certain errors, or return ``NULL`` if the module could not be initialized
-satisfactorily. The init function must return the module object to its caller,
-so that it then gets inserted into ``sys.modules``.
+: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.
@@ -433,23 +480,19 @@ optionally followed by an import of the module::
.. note::
- 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`) can create problems for some extension modules.
- Extension module authors should exercise caution when initializing internal data
- structures.
+ 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 `,
+ 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/xxmodule.c`. This file may be used as a template or simply
+as :file:`Modules/xxlimited.c`. This file may be used as a template or simply
read as an example.
-.. note::
-
- Unlike our ``spam`` example, ``xxmodule`` uses *multi-phase initialization*
- (new in Python 3.5), where a PyModuleDef structure is returned from
- ``PyInit_spam``, and creation of the module is left to the import machinery.
- For details on multi-phase initialization, see :PEP:`489`.
-
.. _compilation:
@@ -502,10 +545,8 @@ calling the Python callback functions from a C callback. Other uses are also
imaginable.
Fortunately, the Python interpreter is easily called recursively, and there is a
-standard interface to call a Python function. (I won't dwell on how to call the
-Python parser with a particular string as input --- if you're interested, have a
-look at the implementation of the :option:`-c` command line option in
-:file:`Modules/main.c` from the Python source code.)
+standard interface to call a Python function. (If you're interested in how to call the
+Python parser with a particular string as input, see :ref:`veryhigh`.)
Calling a Python function is easy. First, the Python program must somehow pass
you the Python function object. You should provide a function (or some other
@@ -790,18 +831,17 @@ Philbrick (philbrick@hks.com)::
{NULL, NULL, 0, NULL} /* sentinel */
};
- static struct PyModuleDef keywdargmodule = {
- PyModuleDef_HEAD_INIT,
- "keywdarg",
- NULL,
- -1,
- keywdarg_methods
+ 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 PyModule_Create(&keywdargmodule);
+ return PyModuleDef_Init(&keywdarg_module);
}
@@ -868,7 +908,7 @@ It is important to call :c:func:`free` at the right time. If a block's address
is forgotten but :c:func:`free` is not called for it, the memory it occupies
cannot be reused until the program terminates. This is called a :dfn:`memory
leak`. On the other hand, if a program calls :c:func:`free` for a block and then
-continues to use the block, it creates a conflict with re-use of the block
+continues to use the block, it creates a conflict with reuse of the block
through another :c:func:`malloc` call. This is called :dfn:`using freed memory`.
It has the same bad consequences as referencing uninitialized data --- core
dumps, wrong results, mysterious crashes.
@@ -896,7 +936,7 @@ and the object is freed.
An alternative strategy is called :dfn:`automatic garbage collection`.
(Sometimes, reference counting is also referred to as a garbage collection
-strategy, hence my use of "automatic" to distinguish the two.) The big
+strategy, hence the use of "automatic" to distinguish the two.) The big
advantage of automatic garbage collection is that the user doesn't need to call
:c:func:`free` explicitly. (Another claimed advantage is an improvement in speed
or memory usage --- this is no hard fact however.) The disadvantage is that for
@@ -1042,7 +1082,14 @@ references to all its items, so when item 1 is replaced, it has to dispose of
the original item 1. Now let's suppose the original item 1 was an instance of a
user-defined class, and let's further suppose that the class defined a
:meth:`!__del__` method. If this class instance has a reference count of 1,
-disposing of it will call its :meth:`!__del__` method.
+disposing of it will call its :meth:`!__del__` method. Internally,
+:c:func:`PyList_SetItem` calls :c:func:`Py_DECREF` on the replaced item,
+which invokes replaced item's corresponding
+:c:member:`~PyTypeObject.tp_dealloc` function. During
+deallocation, :c:member:`~PyTypeObject.tp_dealloc` calls
+:c:member:`~PyTypeObject.tp_finalize`, which is mapped to the
+:meth:`!__del__` method for class instances (see :pep:`442`). This entire
+sequence happens synchronously within the :c:func:`PyList_SetItem` call.
Since it is written in Python, the :meth:`!__del__` method can execute arbitrary
Python code. Could it perhaps do something to invalidate the reference to
@@ -1072,8 +1119,9 @@ why his :meth:`!__del__` methods would fail...
The second case of problems with a borrowed reference is a variant involving
threads. Normally, multiple threads in the Python interpreter can't get in each
-other's way, because there is a global lock protecting Python's entire object
-space. However, it is possible to temporarily release this lock using the macro
+other's way, because there is a :term:`global lock `
+protecting Python's entire object space.
+However, it is possible to temporarily release this lock using the macro
:c:macro:`Py_BEGIN_ALLOW_THREADS`, and to re-acquire it using
:c:macro:`Py_END_ALLOW_THREADS`. This is common around blocking I/O calls, to
let other threads use the processor while waiting for the I/O to complete.
@@ -1259,20 +1307,15 @@ two more lines must be added::
#include "spammodule.h"
The ``#define`` is used to tell the header file that it is being included in the
-exporting module, not a client module. Finally, the module's initialization
-function must take care of initializing the C API pointer array::
+exporting module, not a client module. Finally, the module's :c:data:`mod_exec
+` function must take care of initializing the C API pointer array::
- PyMODINIT_FUNC
- PyInit_spam(void)
+ static int
+ spam_module_exec(PyObject *m)
{
- PyObject *m;
static void *PySpam_API[PySpam_API_pointers];
PyObject *c_api_object;
- m = PyModule_Create(&spammodule);
- if (m == NULL)
- return NULL;
-
/* Initialize the C API pointer array */
PySpam_API[PySpam_System_NUM] = (void *)PySpam_System;
@@ -1280,11 +1323,10 @@ function must take care of initializing the C API pointer array::
c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL);
if (PyModule_Add(m, "_C_API", c_api_object) < 0) {
- Py_DECREF(m);
- return NULL;
+ return -1;
}
- return m;
+ return 0;
}
Note that ``PySpam_API`` is declared ``static``; otherwise the pointer
@@ -1343,20 +1385,16 @@ like this::
All that a client module must do in order to have access to the function
:c:func:`!PySpam_System` is to call the function (or rather macro)
-:c:func:`!import_spam` in its initialization function::
+:c:func:`!import_spam` in its :c:data:`mod_exec ` function::
- PyMODINIT_FUNC
- PyInit_client(void)
+ static int
+ client_module_exec(PyObject *m)
{
- PyObject *m;
-
- m = PyModule_Create(&clientmodule);
- if (m == NULL)
- return NULL;
- if (import_spam() < 0)
- return NULL;
+ if (import_spam() < 0) {
+ return -1;
+ }
/* additional initialization can happen here */
- return m;
+ return 0;
}
The main disadvantage of this approach is that the file :file:`spammodule.h` is
@@ -1367,7 +1405,7 @@ Finally it should be mentioned that Capsules offer additional functionality,
which is especially useful for memory allocation and deallocation of the pointer
stored in a Capsule. The details are described in the Python/C API Reference
Manual in the section :ref:`capsules` and in the implementation of Capsules (files
-:file:`Include/pycapsule.h` and :file:`Objects/pycapsule.c` in the Python source
+:file:`Include/pycapsule.h` and :file:`Objects/capsule.c` in the Python source
code distribution).
.. rubric:: Footnotes
diff --git a/Doc/extending/index.rst b/Doc/extending/index.rst
index 01b4df6d44acff5..3880f4d0b49c492 100644
--- a/Doc/extending/index.rst
+++ b/Doc/extending/index.rst
@@ -12,11 +12,12 @@ 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 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.
+This document assumes basic knowledge about C and Python. For an informal
+introduction to Python, see :ref:`tutorial-index`. :ref:`reference-index`
+gives a more formal definition of the language. :ref:`builtins-index` documents
+the built-in functions and object types, and :ref:`library-index` documents the
+modules (both built-in and written in 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`.
@@ -26,19 +27,9 @@ Recommended third party tools
=============================
This guide only covers the basic tools for creating extensions provided
-as part of this version of CPython. Third party tools like
-`Cython