diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml
index b5b2765e43844f..9b3415fd2b5861 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 6f8fe005621c88..ada5fb0fe64dc2 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/.gitattributes b/.gitattributes
index 5b81d2cb3c90e9..2f5a030981fb94 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -27,8 +27,6 @@ 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
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 1f5f7e57dc4859..a27a7ddd1eeb72 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -29,19 +29,19 @@ 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
# dbm
@@ -150,7 +150,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
@@ -194,7 +194,6 @@ Doc/c-api/stable.rst @encukou
**/*itertools* @rhettinger
**/*collections* @rhettinger
**/*random* @rhettinger
-**/*queue* @rhettinger
**/*bisect* @rhettinger
**/*heapq* @rhettinger
**/*functools* @rhettinger
@@ -205,6 +204,7 @@ Doc/c-api/stable.rst @encukou
**/*ensurepip* @pfmoore @pradyunsg
**/*idlelib* @terryjreedy
+/Doc/library/idle.rst @terryjreedy
**/*typing* @JelleZijlstra @AlexWaygood
@@ -240,7 +240,7 @@ 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
@@ -266,3 +266,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 4cc2f461dbe2f2..03ea959ca14e28 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -7,10 +7,10 @@ Please read this comment in its entirety. It's quite important.
It should be in the following format:
```
-gh-NNNNN: Summary of the changes made
+gh-NNNNNN: Summary of the changes made
```
-Where: gh-NNNNN refers to the GitHub issue number.
+Where: gh-NNNNNN refers to the GitHub issue number.
Most PRs will require an issue number. Trivial changes, like fixing a typo, do not need an issue.
@@ -20,11 +20,11 @@ If this is a backport PR (PR made against branches other than `main`),
please ensure that the PR title is in the following format:
```
-[X.Y]
(GH-NNNN)
+[X.Y] (GH-NNNNNN)
```
-Where: [X.Y] is the branch name, e.g. [3.6].
+Where: [X.Y] is the branch name, for example: [3.13].
-GH-NNNN refers to the PR number from `main`.
+GH-NNNNNN refers to the PR number from `main`.
-->
diff --git a/.github/workflows/add-issue-header.yml b/.github/workflows/add-issue-header.yml
index 570b8779994a0f..3cbc23af578d10 100644
--- a/.github/workflows/add-issue-header.yml
+++ b/.github/workflows/add-issue-header.yml
@@ -18,6 +18,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
issues: write
+ timeout-minutes: 5
steps:
- uses: actions/github-script@v7
with:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1b2677ff6fe889..05d0e3a0c70556 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,26 +1,15 @@
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
@@ -29,137 +18,154 @@ concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}-reusable
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
+ needs: build-context
+ if: needs.build-context.outputs.run-tests == 'true'
steps:
- uses: actions/checkout@v4
- - name: Check for source changes
+ with:
+ persist-credentials: false
+ - uses: actions/setup-python@v5
+ - name: Install dependencies
+ run: |
+ sudo ./.github/workflows/posix-deps-apt.sh
+ sudo apt-get install -yq 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
+ 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: Generate updated ABI files
+ if: ${{ failure() && steps.check.conclusion == 'failure' }}
+ run: |
+ make regen-abidump
+ - uses: actions/upload-artifact@v4
+ name: Publish updated ABI files
+ if: ${{ failure() && steps.check.conclusion == 'failure' }}
+ with:
+ name: abi-data
+ path: ./Doc/data/*.abi
- # 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
- fi
- - name: Compute hash for config cache key
- id: config_hash
+ 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-24.04
+ container:
+ image: ghcr.io/python/autoconf:2024.10.16.11360930377
+ timeout-minutes: 60
+ needs: build-context
+ if: needs.build-context.outputs.run-tests == 'true'
+ steps:
+ - name: Install Git
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
+ apt update && apt install git -yq
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
+ - uses: actions/checkout@v4
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
+ fetch-depth: 1
+ persist-credentials: false
+ - name: Check Autoconf and aclocal versions
run: |
- echo "run-docs=true" >> "${GITHUB_OUTPUT}"
-
- check-docs:
- name: Docs
- needs: check_source
- if: fromJSON(needs.check_source.outputs.run-docs)
- uses: ./.github/workflows/reusable-docs.yml
+ 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:
+ 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-22.04
+ runs-on: ubuntu-24.04
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
+ with:
+ persist-credentials: false
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Runner image version
- run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Restore config.cache
uses: actions/cache@v4
with:
path: config.cache
# Include env.pythonLocation in key to avoid changes in environment when setup-python updates Python
- key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.outputs.config_hash }}-${{ env.pythonLocation }}
- - name: Install Dependencies
+ key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }}-${{ env.pythonLocation }}
+ - name: Install dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: Add ccache to PATH
- run: echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
+ run: echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
- name: Configure ccache action
uses: hendrikmuhs/ccache-action@v1.2
with:
save: 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: 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,78 +192,116 @@ 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
-
- 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-latest
+ arch:
+ - x64
+ free-threading:
+ - false
+ - true
+ include:
+ - os: windows-latest # FIXME(diegorusso): change to os: windows-aarch64
+ arch: arm64
+ free-threading: false
+ - os: windows-latest # FIXME(diegorusso): change to os: windows-aarch64
+ arch: arm64
+ free-threading: true
+ - os: windows-latest
+ arch: Win32
+ free-threading: false
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:
+ name: >- # ${{ '' } is a hack to nest jobs under the same sidebar category
+ Windows MSI${{ '' }}
+ needs: build-context
+ if: fromJSON(needs.build-context.outputs.run-windows-msi)
+ strategy:
+ fail-fast: false
+ matrix:
+ arch:
+ - x86
+ - 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-tests == 'true'
+ strategy:
+ fail-fast: false
+ matrix:
+ # Cirrus and macos-14 are M1, macos-13 is default GHA Intel.
+ # macOS 13 only runs tests against the GIL-enabled CPython.
+ # Cirrus used for upstream, macos-14 for forks.
+ os:
+ - ghcr.io/cirruslabs/macos-runner:sonoma
+ - macos-14
+ - macos-13
+ is-fork: # only used for the exclusion trick
+ - ${{ github.repository_owner != 'python' }}
+ free-threading:
+ - false
+ - true
+ exclude:
+ - os: ghcr.io/cirruslabs/macos-runner:sonoma
+ is-fork: true
+ - os: macos-14
+ is-fork: false
+ - os: macos-13
+ 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"]'
-
- build_ubuntu:
- name: 'Ubuntu'
- 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
+ config_hash: ${{ needs.build-context.outputs.config-hash }}
+ free-threading: ${{ matrix.free-threading }}
+ os: ${{ matrix.os }}
- build_ubuntu_free_threading:
- name: 'Ubuntu (free-threading)'
- 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-tests == '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 \
- --disable-gil
+ config_hash: ${{ needs.build-context.outputs.config-hash }}
+ free-threading: ${{ matrix.free-threading }}
- 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-tests == 'true'
strategy:
fail-fast: false
matrix:
- openssl_ver: [1.1.1w, 3.0.13, 3.1.5, 3.2.1]
+ os: [ubuntu-24.04]
+ openssl_ver: [3.0.15, 3.1.7, 3.2.3, 3.3.2]
env:
OPENSSL_VER: ${{ matrix.openssl_ver }}
MULTISSL_DIR: ${{ github.workspace }}/multissl
@@ -265,34 +309,36 @@ jobs:
LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}/lib
steps:
- uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Runner image version
- run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Restore config.cache
uses: actions/cache@v4
with:
path: config.cache
- key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.outputs.config_hash }}
+ key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }}
- name: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- - name: Install Dependencies
+ - 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
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
+ 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
+ echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
- name: Configure ccache action
uses: hendrikmuhs/ccache-action@v1.2
with:
@@ -306,34 +352,36 @@ jobs:
- name: SSL tests
run: ./python Lib/test/ssltests.py
- build_wasi:
+ build-wasi:
name: 'WASI'
- needs: check_source
- if: needs.check_source.outputs.run_tests == 'true'
+ needs: build-context
+ if: needs.build-context.outputs.run-tests == 'true'
uses: ./.github/workflows/reusable-wasi.yml
with:
- config_hash: ${{ needs.check_source.outputs.config_hash }}
+ config_hash: ${{ needs.build-context.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-tests == 'true'
env:
- OPENSSL_VER: 3.0.13
+ OPENSSL_VER: 3.0.15
PYTHONSTRICTEXTENSIONBUILD: 1
steps:
- uses: actions/checkout@v4
+ 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
@@ -345,33 +393,33 @@ jobs:
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
+ 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
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Restore config.cache
uses: actions/cache@v4
with:
path: ${{ env.CPYTHON_BUILDDIR }}/config.cache
- key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.outputs.config_hash }}
+ key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }}
- name: Configure CPython out-of-tree
working-directory: ${{ env.CPYTHON_BUILDDIR }}
run: |
../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 +428,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
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 +455,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 \
@@ -424,31 +473,36 @@ jobs:
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-tests == 'true'
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-24.04]
env:
- OPENSSL_VER: 3.0.13
+ OPENSSL_VER: 3.0.15
PYTHONSTRICTEXTENSIONBUILD: 1
ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
steps:
- uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Runner image version
- run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Restore config.cache
uses: actions/cache@v4
with:
path: config.cache
- key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.outputs.config_hash }}
+ key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }}
- name: Register gcc problem matcher
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- - name: Install Dependencies
+ - name: Install dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
- name: Set up GCC-10 for ASAN
uses: egor-tensin/setup-gcc@v1
@@ -456,21 +510,21 @@ jobs:
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
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
+ 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
+ echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
- name: Configure ccache action
uses: hendrikmuhs/ccache-action@v1.2
with:
@@ -485,33 +539,30 @@ 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'
+ build-tsan:
+ name: >-
+ Thread sanitizer
+ ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }}
+ needs: build-context
+ if: needs.build-context.outputs.run-tests == 'true'
+ strategy:
+ fail-fast: false
+ matrix:
+ free-threading:
+ - false
+ - true
uses: ./.github/workflows/reusable-tsan.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
+ config_hash: ${{ needs.build-context.outputs.config-hash }}
+ 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'
+ needs: build-context
+ if: needs.build-context.outputs.run-ci-fuzz == 'true'
permissions:
security-events: write
strategy:
@@ -533,8 +584,8 @@ jobs:
output-sarif: true
sanitizer: ${{ matrix.sanitizer }}
- name: Upload crash
- uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success'
+ uses: actions/upload-artifact@v4
with:
name: ${{ matrix.sanitizer }}-artifacts
path: ./out/artifacts
@@ -547,73 +598,68 @@ jobs:
all-required-green: # This job does nothing and is only used for the branch protection
name: All required checks pass
- if: always()
-
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
needs:
- - 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
+ - build-windows
+ - build-windows-msi
+ - build-macos
+ - build-ubuntu
+ - build-ubuntu-ssltests
+ - build-wasi
+ - test-hypothesis
+ - build-asan
+ - build-tsan
- cifuzz
-
- runs-on: ubuntu-latest
+ if: always()
steps:
- name: Check whether the needed jobs succeeded or failed
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe
with:
allowed-failures: >-
- build_ubuntu_ssltests,
+ build-windows-msi,
+ build-ubuntu-ssltests,
+ test-hypothesis,
cifuzz,
- test_hypothesis,
allowed-skips: >-
${{
- !fromJSON(needs.check_source.outputs.run-docs)
+ !fromJSON(needs.build-context.outputs.run-docs)
&& '
check-docs,
'
|| ''
}}
${{
- needs.check_source.outputs.run_tests != 'true'
+ needs.build-context.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,
+ check-autoconf-regen,
+ check-generated-files,
+ build-macos,
+ build-ubuntu,
+ build-ubuntu-ssltests,
+ build-wasi,
+ test-hypothesis,
+ build-asan,
+ build-tsan,
'
|| ''
}}
${{
- !fromJSON(needs.check_source.outputs.run_cifuzz)
+ !fromJSON(needs.build-context.outputs.run-windows-tests)
&& '
- cifuzz,
+ build-windows,
'
|| ''
}}
${{
- !fromJSON(needs.check_source.outputs.run_hypothesis)
+ !fromJSON(needs.build-context.outputs.run-ci-fuzz)
&& '
- test_hypothesis,
+ cifuzz,
'
|| ''
}}
diff --git a/.github/workflows/build_msi.yml b/.github/workflows/build_msi.yml
deleted file mode 100644
index 65d32c734e7745..00000000000000
--- 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
index 43a7afec73884e..a09a30587b35eb 100644
--- a/.github/workflows/documentation-links.yml
+++ b/.github/workflows/documentation-links.yml
@@ -10,9 +10,6 @@ on:
- 'Doc/**'
- '.github/workflows/doc.yml'
-permissions:
- pull-requests: write
-
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
@@ -20,6 +17,10 @@ concurrency:
jobs:
documentation-links:
runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
+ timeout-minutes: 5
+
steps:
- uses: readthedocs/actions/preview@v1
with:
diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml
index 7152cde8f4607c..d08fb9b3e8d6a2 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@v4
+ 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:
@@ -83,6 +108,8 @@ jobs:
CC: ${{ matrix.compiler }}
steps:
- uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- uses: actions/setup-python@v5
with:
python-version: '3.11'
@@ -90,8 +117,7 @@ jobs:
- 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
@@ -113,17 +138,15 @@ jobs:
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@v4
+ with:
+ persist-credentials: false
+ - uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - name: Build with JIT enabled and GIL disabled
+ run: |
+ sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh 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 ccde03f91983df..d74ce8fcc256dc 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -20,6 +20,8 @@ jobs:
steps:
- uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- uses: actions/setup-python@v5
with:
python-version: "3.x"
diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml
index 35996f237814ba..cb5349bb7d4dc0 100644
--- a/.github/workflows/mypy.yml
+++ b/.github/workflows/mypy.yml
@@ -8,9 +8,15 @@ on:
pull_request:
paths:
- ".github/workflows/mypy.yml"
+ - "Lib/_colorize.py"
- "Lib/_pyrepl/**"
- "Lib/test/libregrtest/**"
+ - "Lib/tomllib/**"
+ - "Misc/mypy/**"
+ - "Tools/build/compute-changes.py"
- "Tools/build/generate_sbom.py"
+ - "Tools/build/verify_ensurepip_wheels.py"
+ - "Tools/build/update_file.py"
- "Tools/cases_generator/**"
- "Tools/clinic/**"
- "Tools/jit/**"
@@ -33,11 +39,16 @@ concurrency:
jobs:
mypy:
+ name: Run mypy on ${{ matrix.target }}
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
strategy:
+ fail-fast: false
matrix:
target: [
"Lib/_pyrepl",
"Lib/test/libregrtest",
+ "Lib/tomllib",
"Tools/build",
"Tools/cases_generator",
"Tools/clinic",
@@ -45,15 +56,15 @@ jobs:
"Tools/peg_generator",
"Tools/wasm",
]
- name: Run mypy on ${{ matrix.target }}
- runs-on: ubuntu-latest
- timeout-minutes: 10
steps:
- uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- uses: actions/setup-python@v5
with:
- python-version: "3.11"
+ python-version: "3.13"
cache: pip
cache-dependency-path: Tools/requirements-dev.txt
- run: pip install -r Tools/requirements-dev.txt
+ - run: python3 Misc/mypy/make_symlinks.py --symlink
- run: mypy --config-file ${{ matrix.target }}/mypy.ini
diff --git a/.github/workflows/posix-deps-apt.sh b/.github/workflows/posix-deps-apt.sh
index fb485bd4f82bd2..d5538cd9367ec6 100755
--- a/.github/workflows/posix-deps-apt.sh
+++ b/.github/workflows/posix-deps-apt.sh
@@ -1,11 +1,9 @@
#!/bin/sh
apt-get update
-# autoconf-archive is needed by autoreconf (check_generated_files job)
apt-get -yq install \
build-essential \
pkg-config \
- autoconf-archive \
ccache \
gdb \
lcov \
@@ -15,7 +13,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 066d8593a70cf6..1d9d637ec848a6 100644
--- a/.github/workflows/project-updater.yml
+++ b/.github/workflows/project-updater.yml
@@ -15,6 +15,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
+ fail-fast: false
matrix:
include:
# if an issue has any of these labels, it will be added
diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml
index ff5cbdf3eda749..d7c2580d4e0808 100644
--- a/.github/workflows/require-pr-label.yml
+++ b/.github/workflows/require-pr-label.yml
@@ -4,15 +4,13 @@ on:
pull_request:
types: [opened, reopened, labeled, unlabeled, synchronize]
-permissions:
- issues: write
- pull-requests: write
-
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:
diff --git a/.github/workflows/reusable-context.yml b/.github/workflows/reusable-context.yml
new file mode 100644
index 00000000000000..73dc254edc5fbc
--- /dev/null
+++ b/.github/workflows/reusable-context.yml
@@ -0,0 +1,106 @@
+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'
+ # }}
+ #
+ config-hash:
+ description: Config hash value for use in cache keys
+ value: ${{ jobs.compute-changes.outputs.config-hash }} # str
+ run-docs:
+ description: Whether to build the docs
+ value: ${{ jobs.compute-changes.outputs.run-docs }} # bool
+ run-tests:
+ description: Whether to run the regular tests
+ value: ${{ jobs.compute-changes.outputs.run-tests }} # bool
+ run-windows-tests:
+ description: Whether to run the Windows tests
+ value: ${{ jobs.compute-changes.outputs.run-windows-tests }} # bool
+ run-windows-msi:
+ description: Whether to run the MSI installer smoke tests
+ value: ${{ jobs.compute-changes.outputs.run-windows-msi }} # bool
+ run-ci-fuzz:
+ description: Whether to run the CIFuzz job
+ value: ${{ jobs.compute-changes.outputs.run-ci-fuzz }} # bool
+
+jobs:
+ compute-changes:
+ name: Create context from changed files
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ outputs:
+ config-hash: ${{ steps.config-hash.outputs.hash }}
+ run-ci-fuzz: ${{ steps.changes.outputs.run-ci-fuzz }}
+ run-docs: ${{ steps.changes.outputs.run-docs }}
+ run-tests: ${{ steps.changes.outputs.run-tests }}
+ 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@v5
+ with:
+ python-version: "3"
+
+ - run: >-
+ echo '${{ github.event_name }}'
+
+ - uses: actions/checkout@v4
+ 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 }}
+ CCF_TARGET_REF: ${{ github.base_ref || github.event.repository.default_branch }}
+ CCF_HEAD_REF: ${{ github.event.pull_request.head.sha || github.sha }}
+
+ - name: Compute hash for config cache key
+ id: config-hash
+ run: |
+ echo "hash=${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }}" >> "$GITHUB_OUTPUT"
diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml
index 9e26d7847d2bd3..657e0a6bf662f7 100644
--- a/.github/workflows/reusable-docs.yml
+++ b/.github/workflows/reusable-docs.yml
@@ -1,4 +1,4 @@
-name: Docs
+name: Reusable Docs
on:
workflow_call:
@@ -11,34 +11,45 @@ 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
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
@@ -54,41 +65,26 @@ 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 --fail-on-warning --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
# 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
+ with:
+ persist-credentials: false
- uses: actions/cache@v4
with:
path: ~/.cache/pip
@@ -105,4 +101,4 @@ jobs:
run: make -C Doc/ PYTHON=../python venv
# Use "xvfb-run" since some doctest tests open GUI windows
- name: 'Run documentation doctest'
- run: xvfb-run make -C Doc/ PYTHON=../python SPHINXERRORHANDLING="-W --keep-going" doctest
+ run: xvfb-run make -C Doc/ PYTHON=../python SPHINXERRORHANDLING="--fail-on-warning" doctest
diff --git a/.github/workflows/reusable-macos.yml b/.github/workflows/reusable-macos.yml
index d06a718d199c96..82b14ef854988b 100644
--- a/.github/workflows/reusable-macos.yml
+++ b/.github/workflows/reusable-macos.yml
@@ -1,3 +1,5 @@
+name: Reusable macOS
+
on:
workflow_call:
inputs:
@@ -8,13 +10,18 @@ on:
required: false
type: boolean
default: false
- os-matrix:
- required: false
+ os:
+ description: OS to run the job
+ required: true
type: string
+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,22 @@ 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
+ with:
+ persist-credentials: false
- name: Runner image version
- run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Restore config.cache
uses: actions/cache@v4
with:
path: config.cache
- key: ${{ github.job }}-${{ matrix.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}
+ key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ inputs.config_hash }}
- name: Install Homebrew dependencies
- run: brew install pkg-config openssl@3.0 xz gdbm tcl-tk
+ run: |
+ brew install pkg-config openssl@3.0 xz gdbm tcl-tk@8
+ # 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-tsan.yml b/.github/workflows/reusable-tsan.yml
index 48bd5b547e8cba..1d50c3b2366610 100644
--- a/.github/workflows/reusable-tsan.yml
+++ b/.github/workflows/reusable-tsan.yml
@@ -1,62 +1,91 @@
+name: Reusable Thread Sanitizer
+
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
+ free-threading:
+ description: Whether to use free-threaded mode
+ required: false
+ type: boolean
+ default: false
+
+env:
+ FORCE_COLOR: 1
jobs:
- build_tsan_reusable:
+ build-tsan-reusable:
name: 'Thread sanitizer'
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Runner image version
- run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${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
+ key: ${{ github.job }}-${{ env.IMAGE_OS_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
+ sudo ./llvm.sh 17 # gh-121946: llvm-18 package is temporarily broken
+ sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-17 100
+ sudo update-alternatives --set clang /usr/bin/clang-17
+ sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-17 100
+ sudo update-alternatives --set clang++ /usr/bin/clang++-17
# Reduce ASLR to avoid TSAN crashing
sudo sysctl -w vm.mmap_rnd_bits=28
- - name: TSAN Option Setup
+ - 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
+ echo "TSAN_OPTIONS=log_path=${GITHUB_WORKSPACE}/tsan_log suppressions=${GITHUB_WORKSPACE}/Tools/tsan/suppressions${{
+ fromJSON(inputs.free-threading)
+ && '_free_threading'
+ || ''
+ }}.txt handle_segv=0" >> "$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
+ 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 }}
+ run: >-
+ ./configure
+ --config-cache
+ --with-thread-sanitizer
+ --with-pydebug
+ ${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
- name: Build CPython
run: make -j4
- name: Display build info
run: make pythoninfo
- name: Tests
run: ./python -m test --tsan -j4
+ - name: Display TSAN logs
+ if: always()
+ run: find "${GITHUB_WORKSPACE}" -name 'tsan_log.*' | xargs head -n 1000
+ - name: Archive TSAN logs
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: >-
+ tsan-logs-${{
+ fromJSON(inputs.free-threading)
+ && 'free-threading'
+ || 'default'
+ }}
+ path: tsan_log.*
+ if-no-files-found: ignore
diff --git a/.github/workflows/reusable-ubuntu.yml b/.github/workflows/reusable-ubuntu.yml
index fa450ed3376321..b2625339d19ab6 100644
--- a/.github/workflows/reusable-ubuntu.yml
+++ b/.github/workflows/reusable-ubuntu.yml
@@ -1,46 +1,58 @@
+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
+
+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.15
PYTHONSTRICTEXTENSIONBUILD: 1
TERM: linux
steps:
- uses: actions/checkout@v4
+ 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
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
+ 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
+ echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
- name: Configure ccache action
uses: hendrikmuhs/ccache-action@v1.2
with:
@@ -48,31 +60,36 @@ jobs:
max-size: "200M"
- name: Setup directory envs for out-of-tree builds
run: |
- echo "CPYTHON_RO_SRCDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-ro-srcdir)" >> $GITHUB_ENV
- 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
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: Restore config.cache
uses: actions/cache@v4
with:
path: ${{ env.CPYTHON_BUILDDIR }}/config.cache
- key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}
+ key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ inputs.config_hash }}
- 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"
+ ${{ fromJSON(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 c389fe9e173b38..6beb91e66d4027 100644
--- a/.github/workflows/reusable-wasi.yml
+++ b/.github/workflows/reusable-wasi.yml
@@ -1,3 +1,5 @@
+name: Reusable WASI
+
on:
workflow_call:
inputs:
@@ -5,53 +7,62 @@ on:
required: true
type: string
+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: 22.0.0
+ WASI_SDK_VERSION: 24
WASI_SDK_PATH: /opt/wasi-sdk
CROSS_BUILD_PYTHON: cross-build/build
- CROSS_BUILD_WASI: cross-build/wasm32-wasi
+ CROSS_BUILD_WASI: cross-build/wasm32-wasip1
steps:
- uses: actions/checkout@v4
+ 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@v1
with:
- wasmtime-version: ${{ env.WASMTIME_VERSION }}
+ version: ${{ env.WASMTIME_VERSION }}
- name: "Restore WASI SDK"
id: cache-wasi-sdk
uses: actions/cache@v4
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
+ 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: "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
+ run: echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
- name: "Install Python"
uses: actions/setup-python@v5
with:
python-version: '3.x'
+ - name: "Runner image version"
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: "Restore Python build config.cache"
uses: actions/cache@v4
with:
path: ${{ env.CROSS_BUILD_PYTHON }}/config.cache
- # Include env.pythonLocation in key to avoid changes in environment when setup-python updates Python
- key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}-${{ env.pythonLocation }}
+ # Include env.pythonLocation in key to avoid changes in environment when setup-python updates Python.
+ # Include the hash of `Tools/wasm/wasi.py` as it may change the environment variables.
+ # (Make sure to keep the key in sync with the other config.cache step below.)
+ key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ env.WASI_SDK_VERSION }}-${{ env.WASMTIME_VERSION }}-${{ inputs.config_hash }}-${{ hashFiles('Tools/wasm/wasi.py') }}-${{ env.pythonLocation }}
- name: "Configure build Python"
run: python3 Tools/wasm/wasi.py configure-build-python -- --config-cache --with-pydebug
- name: "Make build Python"
@@ -60,14 +71,14 @@ jobs:
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 }}
+ # Should be kept in sync with the other config.cache step above.
+ key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ env.WASI_SDK_VERSION }}-${{ env.WASMTIME_VERSION }}-${{ inputs.config_hash }}-${{ hashFiles('Tools/wasm/wasi.py') }}-${{ env.pythonLocation }}
- name: "Configure host"
# `--with-pydebug` inferred from configure-build-python
run: python3 Tools/wasm/wasi.py configure-host -- --config-cache
- name: "Make host"
run: python3 Tools/wasm/wasi.py make-host
- name: "Display build info"
- run: make --directory ${{ env.CROSS_BUILD_WASI }} pythoninfo
+ run: make --directory "${CROSS_BUILD_WASI}" pythoninfo
- 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 00000000000000..bc0414d1bbcd8f
--- /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-latest
+ timeout-minutes: 60
+ env:
+ ARCH: ${{ inputs.arch }}
+ IncludeFreethreaded: true
+ steps:
+ - uses: actions/checkout@v4
+ 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 c0209e0e1c92e9..5485a0169130b0 100644
--- a/.github/workflows/reusable-windows.yml
+++ b/.github/workflows/reusable-windows.yml
@@ -1,53 +1,56 @@
+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' || '' }}
-
- 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
+ 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}"
+ ${{ fromJSON(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
+ ${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
+ shell: bash
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index f97587e68cbbe4..febb2dd823a8fe 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -4,14 +4,12 @@ on:
schedule:
- cron: "0 */6 * * *"
-permissions:
- pull-requests: write
-
jobs:
stale:
if: github.repository_owner == 'python'
-
runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
timeout-minutes: 10
steps:
diff --git a/.github/workflows/verify-ensurepip-wheels.yml b/.github/workflows/verify-ensurepip-wheels.yml
index 83b007f1c9c2ef..463e7bf3355cc3 100644
--- a/.github/workflows/verify-ensurepip-wheels.yml
+++ b/.github/workflows/verify-ensurepip-wheels.yml
@@ -26,6 +26,8 @@ jobs:
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- uses: actions/setup-python@v5
with:
python-version: '3'
diff --git a/.github/zizmor.yml b/.github/zizmor.yml
new file mode 100644
index 00000000000000..9b42b47cc85545
--- /dev/null
+++ b/.github/zizmor.yml
@@ -0,0 +1,10 @@
+# Configuration for the zizmor static analysis tool, run via pre-commit in CI
+# https://woodruffw.github.io/zizmor/configuration/
+rules:
+ dangerous-triggers:
+ ignore:
+ - documentation-links.yml
+ unpinned-uses:
+ config:
+ policies:
+ "*": ref-pin
diff --git a/.gitignore b/.gitignore
index 8872e9d5508ff1..c945904f6b405b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@ tags
TAGS
.vs/
.vscode/
+.cache/
gmon.out
.coverage
.mypy_cache/
@@ -137,11 +138,12 @@ Tools/unicode/data/
# hendrikmuhs/ccache-action@v1
/.ccache
/cross-build/
-/jit_stencils.h
+/jit_stencils*.h
/platform
/profile-clean-stamp
/profile-run-stamp
/profile-bolt-stamp
+/profile-gen-stamp
/pybuilddir.txt
/pyconfig.h
/python-config
@@ -169,5 +171,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 fde9d9149bf62b..66b8aa14b9283a 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,26 +1,33 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.3.4
+ rev: v0.11.6
hooks:
- id: ruff
- name: Run Ruff on Lib/test/
+ name: Run Ruff (lint) on Doc/
+ args: [--exit-non-zero-on-fix]
+ files: ^Doc/
+ - id: ruff
+ name: Run Ruff (lint) on Lib/test/
args: [--exit-non-zero-on-fix]
files: ^Lib/test/
- id: ruff
- name: Run Ruff on Argument Clinic
+ 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-format
+ name: Run Ruff (format) on Doc/
+ args: [--check]
+ files: ^Doc/
- repo: https://github.com/psf/black-pre-commit-mirror
- rev: 24.4.2
+ rev: 25.1.0
hooks:
- id: black
name: Run Black on Tools/jit/
files: ^Tools/jit/
- language_version: python3.12
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.5.0
+ rev: v5.0.0
hooks:
- id: check-case-conflict
- id: check-merge-conflict
@@ -33,8 +40,13 @@ repos:
- id: trailing-whitespace
types_or: [c, inc, python, rst]
+ - repo: https://github.com/woodruffw/zizmor-pre-commit
+ rev: v1.6.0
+ hooks:
+ - id: zizmor
+
- repo: https://github.com/sphinx-contrib/sphinx-lint
- rev: v0.9.1
+ rev: v1.0.0
hooks:
- id: sphinx-lint
args: [--enable=default-role]
diff --git a/.readthedocs.yml b/.readthedocs.yml
index 59830c79a404e0..a57de00544e4e3 100644
--- a/.readthedocs.yml
+++ b/.readthedocs.yml
@@ -8,7 +8,7 @@ sphinx:
configuration: Doc/conf.py
build:
- os: ubuntu-22.04
+ os: ubuntu-24.04
tools:
python: "3"
@@ -26,6 +26,9 @@ build:
exit 183;
fi
+ - asdf plugin add uv
+ - asdf install uv latest
+ - asdf global uv latest
- make -C Doc venv html
- mkdir _readthedocs
- mv Doc/build/html _readthedocs/html
diff --git a/Android/README.md b/Android/README.md
index f5f463ca116589..6cabd6ba5d6844 100644
--- a/Android/README.md
+++ b/Android/README.md
@@ -1,19 +1,22 @@
# Python for Android
-These instructions are only needed if you're planning to compile Python for
-Android yourself. Most users should *not* need to do this. 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,23 @@ 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)
## 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 +66,8 @@ To do all steps in a single command, run:
./android.py build HOST
```
-In the end you should have a build Python in `cross-build/build`, and an Android
-build in `cross-build/HOST`.
+In the end you should have a build Python in `cross-build/build`, and a host
+Python in `cross-build/HOST`.
You can use `--` as a separator for any of the `configure`-related commands –
including `build` itself – to pass arguments to the underlying `configure`
@@ -78,20 +79,84 @@ 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, and
+ a DISPLAY environment variable pointing at an X server. Xvfb is acceptable.
+
+The test suite can usually be run on a device with 2 GB of RAM, but this is
+borderline, so you may need to increase it to 4 GB. As of Android
+Studio Koala, 2 GB is the default for all emulators, although the user interface
+may indicate otherwise. Locate the emulator's directory under `~/.android/avd`,
+and find `hw.ramSize` in both config.ini and hardware-qemu.ini. Either set these
+manually to the same value, or use the Android Studio Device Manager, which will
+update both files.
+
+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`.
+
+
+## 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 545d559d93ab36..181fcea8f40783 100644
--- a/Android/android-env.sh
+++ b/Android/android-env.sh
@@ -1,10 +1,10 @@
# 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
+: "${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.
@@ -24,23 +24,23 @@ 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.1.12297006
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" ]; 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"
@@ -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 0a1393e61ddb0e..3f48b42aa17571 100755
--- a/Android/android.py
+++ b/Android/android.py
@@ -1,33 +1,69 @@
#!/usr/bin/env python3
+import asyncio
import argparse
import os
import re
+import shlex
import shutil
+import signal
import subprocess
import sys
import sysconfig
+from asyncio import wait_for
+from contextlib import asynccontextmanager
+from datetime import datetime, timezone
+from glob import glob
from os.path import basename, relpath
from pathlib import Path
+from subprocess import CalledProcessError
from tempfile import TemporaryDirectory
+
SCRIPT_NAME = Path(__file__).name
-CHECKOUT = Path(__file__).resolve().parent.parent
+ANDROID_DIR = Path(__file__).resolve().parent
+CHECKOUT = ANDROID_DIR.parent
+TESTBED_DIR = ANDROID_DIR / "testbed"
CROSS_BUILD_DIR = CHECKOUT / "cross-build"
+HOSTS = ["aarch64-linux-android", "x86_64-linux-android"]
+APP_ID = "org.python.testbed"
+DECODE_ARGS = ("UTF-8", "backslashreplace")
+
+
+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 "")
+)
+
+logcat_started = False
-def delete_if_exists(path):
- if path.exists():
+
+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,10 +72,14 @@ 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()
+ original_env = env.copy()
+
if host:
- env_script = CHECKOUT / "Android/android-env.sh"
+ env_script = ANDROID_DIR / "android-env.sh"
env_output = subprocess.run(
f"set -eu; "
f"HOST={host}; "
@@ -60,15 +100,13 @@ def run(command, *, host=None, **kwargs):
print(line)
env[key] = value
- if env == os.environ:
+ if env == original_env:
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)
+ if log:
+ print(">", " ".join(map(str, command)))
+ return subprocess.run(command, env=env, **kwargs)
def build_python_path():
@@ -85,7 +123,9 @@ def build_python_path():
def configure_build_python(context):
- os.chdir(subdir("build", clean=context.clean))
+ if context.clean:
+ clean("build")
+ os.chdir(subdir("build", create=True))
command = [relpath(CHECKOUT / "configure")]
if context.args:
@@ -98,35 +138,33 @@ def make_build_python(context):
run(["make", "-j", str(os.cpu_count())])
-def unpack_deps(host):
+def unpack_deps(host, prefix_dir):
deps_url = "https://github.com/beeware/cpython-android-source-deps/releases/download"
- for name_ver in ["bzip2-1.0.8-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-2", "libffi-3.4.4-3", "openssl-3.0.15-4",
+ "sqlite-3.49.1-0", "xz-5.4.6-1"]:
filename = f"{name_ver}-{host}.tar.gz"
download(f"{deps_url}/{name_ver}/{filename}")
- run(["tar", "-xf", filename])
+ shutil.unpack_archive(filename, prefix_dir)
os.remove(filename)
def download(url, target_dir="."):
out_path = f"{target_dir}/{basename(url)}"
- run(["curl", "-Lf", "-o", out_path, url])
+ run(["curl", "-Lf", "--retry", "5", "--retry-all-errors", "-o", out_path, url])
return out_path
def configure_host_python(context):
- host_dir = subdir(context.host, clean=context.clean)
+ if context.clean:
+ clean(context.host)
+ host_dir = subdir(context.host, create=True)
prefix_dir = host_dir / "prefix"
if not prefix_dir.exists():
prefix_dir.mkdir()
- os.chdir(prefix_dir)
- unpack_deps(context.host)
-
- build_dir = host_dir / "build"
- build_dir.mkdir(exist_ok=True)
- os.chdir(build_dir)
+ unpack_deps(context.host, prefix_dir)
+ os.chdir(host_dir)
command = [
# Basic cross-compiling configuration
relpath(CHECKOUT / "configure"),
@@ -150,10 +188,17 @@ def configure_host_python(context):
def make_host_python(context):
+ # 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(context.host)
- os.chdir(host_dir / "build")
+ prefix_dir = host_dir / "prefix"
+ for pattern in ("include/python*", "lib/libpython*", "lib/python*"):
+ delete_glob(f"{prefix_dir}/{pattern}")
+
+ os.chdir(host_dir)
run(["make", "-j", str(os.cpu_count())], host=context.host)
- run(["make", "install", f"prefix={host_dir}/prefix"], host=context.host)
+ run(["make", "install", f"prefix={prefix_dir}"], host=context.host)
def build_all(context):
@@ -163,37 +208,416 @@ def build_all(context):
step(context)
+def clean(host):
+ delete_glob(CROSS_BUILD_DIR / host)
+
+
def clean_all(context):
- delete_if_exists(CROSS_BUILD_DIR)
+ for host in HOSTS + ["build"]:
+ clean(host)
+
+
+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, 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
+
+ # The wrapper version isn't important, as any version of the wrapper can
+ # download any version of Gradle. The Gradle version actually used for the
+ # build is specified in testbed/gradle/wrapper/gradle-wrapper.properties.
+ version = "8.9.0"
+
+ for path in paths:
+ out_path = TESTBED_DIR / path
+ out_path.parent.mkdir(exist_ok=True)
+ download(
+ f"https://raw.githubusercontent.com/gradle/gradle/v{version}/{path}",
+ out_path.parent,
+ )
os.chmod(out_path, 0o755)
- with TemporaryDirectory(prefix=SCRIPT_NAME) as temp_dir:
- 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"])
+# run_testbed will build the app automatically, but it's useful to have this as
+# a separate command to allow running the app outside of this script.
+def build_testbed(context):
+ setup_sdk()
+ setup_testbed()
+ run(
+ [gradlew, "--console", "plain", "packageDebug", "packageDebugAndroidTest"],
+ cwd=TESTBED_DIR,
+ )
-def main():
+
+# 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.
+ args = [adb, "-s", serial, "logcat", "--pid", pid, "--format", "tag"]
+ hidden_output = []
+ async with async_process(
+ *args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+ ) as process:
+ while line := (await process.stdout.readline()).decode(*DECODE_ARGS):
+ if match := re.fullmatch(r"([A-Z])/(.*)", line, re.DOTALL):
+ level, message = match.groups()
+ else:
+ # If the regex doesn't match, this is probably the second or
+ # subsequent line of a multi-line message. Python won't produce
+ # such messages, but other components might.
+ level, message = None, line
+
+ # 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 level in ["W", "E", "F"] # WARNING, ERROR, FATAL (aka ASSERT)
+ else sys.stdout
+ )
+
+ # To simplify automated processing of the output, e.g. a buildbot
+ # posting a failure notice on a GitHub PR, we strip the level and
+ # tag indicators from Python's stdout and stderr.
+ for prefix in ["python.stdout: ", "python.stderr: "]:
+ if message.startswith(prefix):
+ global logcat_started
+ logcat_started = True
+ stream.write(message.removeprefix(prefix))
+ break
+ else:
+ if context.verbose:
+ # Non-Python messages add a lot of noise, but they may
+ # sometimes help explain a failure.
+ stream.write(line)
+ else:
+ hidden_output.append(line)
+
+ # 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 a message from Python yet.
+ status = await wait_for(process.wait(), timeout=1)
+ if status != 0 and not logcat_started:
+ raise CalledProcessError(status, args, "".join(hidden_output))
+
+
+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
+
+ args = [
+ gradlew, "--console", "plain", f"{task_prefix}DebugAndroidTest",
+ "-Pandroid.testInstrumentationRunnerArguments.pythonArgs="
+ + shlex.join(context.args),
+ ]
+ hidden_output = []
+ 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 context.verbose or line.startswith('Preparing "Install'):
+ sys.stdout.write(line)
+ else:
+ hidden_output.append(line)
+
+ status = await wait_for(process.wait(), timeout=1)
+ if status == 0:
+ exit(0)
+ else:
+ raise CalledProcessError(status, args)
+ finally:
+ # If logcat never started, then something has gone badly wrong, so the
+ # user probably wants to see the Gradle output even in non-verbose mode.
+ if hidden_output and not logcat_started:
+ sys.stdout.write("".join(hidden_output))
+
+ # Gradle does not stop the tests when interrupted.
+ if context.connected:
+ stop_app(context.connected)
+
+
+async def run_testbed(context):
+ 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:
+ # 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:
+ temp_dir = Path(temp_dir)
+
+ # Include all tracked files from the Android directory.
+ for line in run(
+ ["git", "ls-files"],
+ cwd=ANDROID_DIR, capture_output=True, text=True, log=False,
+ ).stdout.splitlines():
+ src = ANDROID_DIR / line
+ dst = temp_dir / line
+ dst.parent.mkdir(parents=True, exist_ok=True)
+ shutil.copy2(src, dst, follow_symlinks=False)
+
+ # Include anything from the prefix directory which could be useful
+ # either for embedding Python in an app, or building third-party
+ # packages against it.
+ for rel_dir, patterns in [
+ ("include", ["openssl*", "python*", "sqlite*"]),
+ ("lib", ["engines-3", "libcrypto*.so", "libpython*", "libsqlite*",
+ "libssl*.so", "ossl-modules", "python*"]),
+ ("lib/pkgconfig", ["*crypto*", "*ssl*", "*python*", "*sqlite*"]),
+ ]:
+ for pattern in patterns:
+ for src in glob(f"{prefix_dir}/{rel_dir}/{pattern}"):
+ dst = temp_dir / relpath(src, prefix_dir.parent)
+ dst.parent.mkdir(parents=True, exist_ok=True)
+ if Path(src).is_dir():
+ shutil.copytree(
+ src, dst, symlinks=True,
+ ignore=lambda *args: ["__pycache__"]
+ )
+ else:
+ shutil.copy2(src, dst, follow_symlinks=False)
+
+ dist_dir = subdir(context.host, "dist", create=True)
+ package_path = shutil.make_archive(
+ f"{dist_dir}/python-{version}-{context.host}", "gztar", temp_dir
+ )
+ print(f"Wrote {package_path}")
+
+
+# Handle SIGTERM the same way as SIGINT. This ensures that if we're terminated
+# by the buildbot worker, we'll make an attempt to clean up our subprocesses.
+def install_signal_handler():
+ 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")
+
+ # Subcommands
build = subcommands.add_parser("build", help="Build everything")
configure_build = subcommands.add_parser("configure-build",
help="Run `configure` for the "
@@ -205,32 +629,94 @@ def main():
make_host = subcommands.add_parser("make-host",
help="Run `make` for Android")
subcommands.add_parser(
- "clean", help="Delete the cross-build directory")
+ "clean", help="Delete all build and prefix directories")
subcommands.add_parser(
- "setup-testbed", help="Download the testbed Gradle wrapper")
+ "build-testbed", help="Build the testbed app")
+ test = subcommands.add_parser(
+ "test", help="Run the test suite")
+ package = subcommands.add_parser("package", help="Make a release package")
+ # Common arguments
for subcommand in build, configure_build, configure_host:
subcommand.add_argument(
"--clean", action="store_true", default=False, dest="clean",
- help="Delete any relevant directories before building")
- for subcommand in build, configure_host, make_host:
+ help="Delete the relevant build and prefix directories first")
+ for subcommand in [build, configure_host, make_host, package]:
subcommand.add_argument(
- "host", metavar="HOST",
- choices=["aarch64-linux-android", "x86_64-linux-android"],
+ "host", metavar="HOST", choices=HOSTS,
help="Host triplet: choices=[%(choices)s]")
for subcommand in build, configure_build, configure_host:
subcommand.add_argument("args", nargs="*",
help="Extra arguments to pass to `configure`")
- 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
+ test.add_argument(
+ "-v", "--verbose", action="count", default=0,
+ help="Show Gradle output, and non-Python logcat messages. "
+ "Use twice to include high-volume messages which are rarely useful.")
+ 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(
+ "args", nargs="*", help=f"Arguments for `python -m test`. "
+ f"Separate them from {SCRIPT_NAME}'s own arguments with `--`.")
+
+ 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()
+ dispatch = {
+ "configure-build": configure_build_python,
+ "make-build": make_build_python,
+ "configure-host": configure_host_python,
+ "make-host": make_host_python,
+ "build": build_all,
+ "clean": clean_all,
+ "build-testbed": build_testbed,
+ "test": run_testbed,
+ "package": package,
+ }
+
+ try:
+ result = dispatch[context.subcommand](context)
+ 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)
+ stream = getattr(sys, stream_name)
+ if content:
+ stream.write(content)
+ if not content.endswith("\n"):
+ stream.write("\n")
+
+ # Format the command so it can be copied into a shell. shlex uses single
+ # quotes, so we surround the whole command with double quotes.
+ args_joined = (
+ e.cmd if isinstance(e.cmd, str)
+ else " ".join(shlex.quote(str(arg)) for arg in e.cmd)
+ )
+ print(
+ f'Command "{args_joined}" returned exit status {e.returncode}'
+ )
if __name__ == "__main__":
diff --git a/Android/testbed/.gitignore b/Android/testbed/.gitignore
index b9a7d611c943cf..7c57aee58c160a 100644
--- a/Android/testbed/.gitignore
+++ b/Android/testbed/.gitignore
@@ -1,18 +1,19 @@
-# The Gradle wrapper should be downloaded by running `../android.py setup-testbed`.
+# The Gradle wrapper can be downloaded by running the `test` or `build-testbed`
+# commands of android.py.
/gradlew
/gradlew.bat
/gradle/wrapper/gradle-wrapper.jar
+# The repository's top-level .gitignore file ignores all .idea directories, but
+# we want to keep any files which can't be regenerated from the Gradle
+# configuration.
+!.idea/
+/.idea/*
+!/.idea/inspectionProfiles
+
*.iml
.gradle
/local.properties
-/.idea/caches
-/.idea/deploymentTargetDropdown.xml
-/.idea/libraries
-/.idea/modules.xml
-/.idea/workspace.xml
-/.idea/navEditor.xml
-/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
diff --git a/Android/testbed/.idea/inspectionProfiles/Project_Default.xml b/Android/testbed/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 00000000000000..220d9ed4ef20f7
--- /dev/null
+++ b/Android/testbed/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Android/testbed/app/build.gradle.kts b/Android/testbed/app/build.gradle.kts
index 7690d3fd86b2fd..c627cb1b0e0b22 100644
--- a/Android/testbed/app/build.gradle.kts
+++ b/Android/testbed/app/build.gradle.kts
@@ -1,45 +1,125 @@
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("$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",
+ "x86_64-linux-android" to "x86_64",
+)
+
+// Discover prefixes.
+val prefixes = ArrayList()
+if (inSourceTree) {
+ for ((triplet, _) in KNOWN_ABIS.entries) {
+ val prefix = file("$PYTHON_CROSS_DIR/$triplet/prefix")
+ if (prefix.exists()) {
+ prefixes.add(prefix)
}
}
- 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+)""".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__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
defaultConfig {
applicationId = "org.python.testbed"
- minSdk = 21
+
+ minSdk = androidEnvFile.useLines {
+ for (line in it) {
+ """api_level:=(\d+)""".toRegex().find(line)?.let {
+ return@useLines it.groupValues[1].toInt()
+ }
+ }
+ throw GradleException("Failed to find API level in $androidEnvFile")
+ }
targetSdk = 34
+
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")
}
@@ -55,47 +135,88 @@ android {
kotlinOptions {
jvmTarget = "1.8"
}
+
+ testOptions {
+ managedDevices {
+ localDevices {
+ 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 "aosp"
+ }
+
+ 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 }
+ }
+ }
+ }
+ }
+ }
}
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")
}
// 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")
}
+
+ duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+ exclude("**/__pycache__")
}
}
- 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 00000000000000..0e888ab71d87da
--- /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 context =
+ InstrumentationRegistry.getInstrumentation().targetContext
+ val args =
+ InstrumentationRegistry.getArguments().getString("pythonArgs", "")
+ val status = PythonTestRunner(context).run(args)
+ 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 1d5df9a73465b6..6d5ccd96f8ae29 100644
--- a/Android/testbed/app/src/main/c/CMakeLists.txt
+++ b/Android/testbed/app/src/main/c/CMakeLists.txt
@@ -1,9 +1,14 @@
cmake_minimum_required(VERSION 3.4.1)
project(testbed)
-set(PREFIX_DIR ${PYTHON_CROSS_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}/prefix)
-include_directories(${PREFIX_DIR}/include/python${PYTHON_VERSION})
-link_directories(${PREFIX_DIR}/lib)
+# Resolve variables from the command line.
+string(
+ REPLACE {{triplet}} ${CMAKE_LIBRARY_ARCHITECTURE}
+ PYTHON_PREFIX_DIR ${PYTHON_PREFIX_DIR}
+)
+
+include_directories(${PYTHON_PREFIX_DIR}/include/python${PYTHON_VERSION})
+link_directories(${PYTHON_PREFIX_DIR}/lib)
link_libraries(log python${PYTHON_VERSION})
add_library(main_activity SHARED main_activity.c)
diff --git a/Android/testbed/app/src/main/c/main_activity.c b/Android/testbed/app/src/main/c/main_activity.c
index 73aba4164d000f..ec7f93a3e5ee13 100644
--- a/Android/testbed/app/src/main/c/main_activity.c
+++ b/Android/testbed/app/src/main/c/main_activity.c
@@ -34,9 +34,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,9 +87,11 @@ 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))) {
@@ -100,7 +105,7 @@ JNIEXPORT void JNICALL Java_org_python_testbed_MainActivity_redirectStdioToLogca
}
-// --- Python intialization ----------------------------------------------------
+// --- Python initialization ---------------------------------------------------
static PyStatus set_config_string(
JNIEnv *env, PyConfig *config, wchar_t **config_str, jstring value
@@ -115,7 +120,7 @@ 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(
+JNIEXPORT int JNICALL Java_org_python_testbed_PythonTestRunner_runPython(
JNIEnv *env, jobject obj, jstring home, jstring runModule
) {
PyConfig config;
@@ -125,13 +130,13 @@ JNIEXPORT void JNICALL Java_org_python_testbed_MainActivity_runPython(
status = set_config_string(env, &config, &config.home, home);
if (PyStatus_Exception(status)) {
throw_status(env, status);
- return;
+ return 1;
}
status = set_config_string(env, &config, &config.run_module, runModule);
if (PyStatus_Exception(status)) {
throw_status(env, status);
- return;
+ return 1;
}
// Some tests generate SIGPIPE and SIGXFSZ, which should be ignored.
@@ -140,8 +145,8 @@ JNIEXPORT void JNICALL Java_org_python_testbed_MainActivity_runPython(
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 5a590d5d04e954..c4bf6cbe83d8cd 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,56 @@
package org.python.testbed
+import android.content.Context
import android.os.*
import android.system.Os
import android.widget.TextView
import androidx.appcompat.app.*
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("-W -uall")
+ findViewById(R.id.tvHello).text = "Exit status $status"
+ }
+}
+
+
+class PythonTestRunner(val context: Context) {
+ /** @param args Extra arguments for `python -m test`.
+ * @return The Python exit status: zero if the tests passed, nonzero if
+ * they failed. */
+ fun run(args: String = "") : Int {
+ Os.setenv("PYTHON_ARGS", args, true)
// 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"
+
+ // The main module is in src/main/python/main.py.
+ return runPython(pythonHome.toString(), "main")
}
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)
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,7 +61,7 @@ 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
@@ -57,5 +75,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, runModule: String) : Int
+}
diff --git a/Android/testbed/app/src/main/python/main.py b/Android/testbed/app/src/main/python/main.py
index a1b6def34ede81..d6941b14412fcc 100644
--- a/Android/testbed/app/src/main/python/main.py
+++ b/Android/testbed/app/src/main/python/main.py
@@ -1,17 +1,32 @@
+import os
import runpy
+import shlex
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.
+# 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.
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",
-]
+sys.argv[1:] = shlex.split(os.environ["PYTHON_ARGS"])
+
+# The test module will call sys.exit to indicate whether the tests passed.
runpy.run_module("test")
diff --git a/Android/testbed/build.gradle.kts b/Android/testbed/build.gradle.kts
index 53f4a67287fcc5..4d1d6f87594da3 100644
--- a/Android/testbed/build.gradle.kts
+++ b/Android/testbed/build.gradle.kts
@@ -1,5 +1,5 @@
// 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("com.android.application") version "8.6.1" apply false
id("org.jetbrains.kotlin.android") version "1.9.22" apply false
-}
\ No newline at end of file
+}
diff --git a/Android/testbed/gradle.properties b/Android/testbed/gradle.properties
index 3c5031eb7d63f7..e9f345c8c26250 100644
--- a/Android/testbed/gradle.properties
+++ b/Android/testbed/gradle.properties
@@ -20,4 +20,9 @@ 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
+android.nonTransitiveRClass=true
+
+# 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 2dc3339a3ef213..36529c896426b0 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-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/Doc/.ruff.toml b/Doc/.ruff.toml
new file mode 100644
index 00000000000000..111ce03b91df38
--- /dev/null
+++ b/Doc/.ruff.toml
@@ -0,0 +1,42 @@
+target-version = "py312" # Align with the version in oldest_supported_sphinx
+fix = true
+output-format = "full"
+line-length = 79
+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 dd068c520ad60c..c8a749a02a89ec 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"
@@ -140,14 +142,19 @@ pydoc-topics: build
@echo "Building finished; now run this:" \
"cp build/pydoc-topics/topics.py ../Lib/pydoc_data/topics.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
@@ -164,92 +171,150 @@ venv:
echo "To recreate it, remove it first with \`make clean-venv'."; \
else \
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-pdf 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
+ (cd build/latex; $(MAKE) clean && $(MAKE) --jobs=$$((`nproc`+1)) --output-sync LATEXMKOPTS='-quiet' all-pdf && $(MAKE) FMT=pdf zip bz2)
cp build/latex/docs-pdf.zip dist/python-$(DISTVERSION)-docs-pdf-a4.zip
cp build/latex/docs-pdf.tar.bz2 dist/python-$(DISTVERSION)-docs-pdf-a4.tar.bz2
+ @echo "Build finished and archived!"
- # 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 +324,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 +332,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 a3bb5fa5445c23..2d1148753e0c6b 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 5e6160ff2700ed..8f635d7f743a98 100644
--- a/Doc/about.rst
+++ b/Doc/about.rst
@@ -1,10 +1,11 @@
-=====================
-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/
@@ -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/c-api/allocation.rst b/Doc/c-api/allocation.rst
index b3609c233156b6..0deb632f0df661 100644
--- a/Doc/c-api/allocation.rst
+++ b/Doc/c-api/allocation.rst
@@ -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,6 +53,10 @@ Allocating Objects on the Heap
fields into the same allocation decreases the number of allocations,
improving the memory management efficiency.
+ 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:function:: void PyObject_Del(void *op)
diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst
index 834aae9372fe3b..9420ae050814c5 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`.
@@ -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:
@@ -627,6 +639,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 +656,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 1e1cabdf242bd1..d3081894eadaf5 100644
--- a/Doc/c-api/buffer.rst
+++ b/Doc/c-api/buffer.rst
@@ -26,17 +26,19 @@ characteristic of being backed by a possibly large memory buffer. It is
then desirable, in some situations, to access that buffer directly and
without intermediate copying.
-Python provides such a facility at the C level in the form of the :ref:`buffer
-protocol `. This protocol has two sides:
+Python provides such a facility at the C and Python level in the form of the
+:ref:`buffer protocol `. This protocol has two sides:
.. index:: single: PyBufferProcs (C type)
- on the producer side, a type can export a "buffer interface" which allows
objects of that type to expose information about their underlying buffer.
- This interface is described in the section :ref:`buffer-structs`;
+ This interface is described in the section :ref:`buffer-structs`; for
+ Python see :ref:`python-buffer-protocol`.
- on the consumer side, several means are available to obtain a pointer to
- the raw underlying data of an object (for example a method parameter).
+ the raw underlying data of an object (for example a method parameter). For
+ Python see :class:`memoryview`.
Simple objects such as :class:`bytes` and :class:`bytearray` expose their
underlying buffer in byte-oriented form. Other forms are possible; for example,
@@ -62,6 +64,10 @@ In both cases, :c:func:`PyBuffer_Release` must be called when the buffer
isn't needed anymore. Failure to do so could lead to various issues such as
resource leaks.
+.. versionadded:: 3.12
+
+ The buffer protocol is now accessible in Python, see
+ :ref:`python-buffer-protocol` and :class:`memoryview`.
.. _buffer-structure:
@@ -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,8 @@ 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_FORMAT
@@ -265,8 +271,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 456f7d89bca03c..9045689a6be567 100644
--- a/Doc/c-api/bytearray.rst
+++ b/Doc/c-api/bytearray.rst
@@ -42,17 +42,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/cell.rst b/Doc/c-api/cell.rst
index f8cd0344fdd1c0..61eb994c370946 100644
--- a/Doc/c-api/cell.rst
+++ b/Doc/c-api/cell.rst
@@ -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 968c472219c643..6eae24b38fae48 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
@@ -96,8 +98,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 +146,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
diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst
index 5a0474869071d9..67d0c5f144e075 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/datetime.rst b/Doc/c-api/datetime.rst
index 97522da773477e..d2d4d5309c7098 100644
--- a/Doc/c-api/datetime.rst
+++ b/Doc/c-api/datetime.rst
@@ -318,10 +318,10 @@ 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`.
diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst
index 03f3d28187bfe9..ce73fa0cc60ebb 100644
--- a/Doc/c-api/dict.rst
+++ b/Doc/c-api/dict.rst
@@ -156,7 +156,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,6 +191,7 @@ 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
@@ -205,7 +206,7 @@ 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
+ Similar to :meth:`dict.pop`, but without the default value and
not raising :exc:`KeyError` if the key missing.
.. versionadded:: 3.13
@@ -289,6 +290,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)
diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst
index 499bfb47cc4be5..fc2336d120c259 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).
@@ -733,7 +733,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*
@@ -1004,6 +1004,7 @@ the variables:
single: PyExc_OverflowError (C var)
single: PyExc_PermissionError (C var)
single: PyExc_ProcessLookupError (C var)
+ single: PyExc_PythonFinalizationError (C var)
single: PyExc_RecursionError (C var)
single: PyExc_ReferenceError (C var)
single: PyExc_RuntimeError (C var)
@@ -1096,6 +1097,8 @@ the variables:
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_ProcessLookupError` | :exc:`ProcessLookupError` | |
+-----------------------------------------+---------------------------------+----------+
+| :c:data:`PyExc_PythonFinalizationError` | :exc:`PythonFinalizationError` | |
++-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_RecursionError` | :exc:`RecursionError` | |
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_ReferenceError` | :exc:`ReferenceError` | |
diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst
index 4f6ac0d8175c6b..1da37a5bcaeef9 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
diff --git a/Doc/c-api/frame.rst b/Doc/c-api/frame.rst
index 82e0980ad753d0..1a52e146a69751 100644
--- a/Doc/c-api/frame.rst
+++ b/Doc/c-api/frame.rst
@@ -121,17 +121,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,6 +140,26 @@ 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.
Internal Frames
^^^^^^^^^^^^^^^
diff --git a/Doc/c-api/function.rst b/Doc/c-api/function.rst
index e7fb5090c09933..58792edeed25e3 100644
--- a/Doc/c-api/function.rst
+++ b/Doc/c-api/function.rst
@@ -145,12 +145,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
diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst
index 621da3eb069949..d1f0982b818931 100644
--- a/Doc/c-api/gcsupport.rst
+++ b/Doc/c-api/gcsupport.rst
@@ -277,7 +277,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/hash.rst b/Doc/c-api/hash.rst
index ddf0b3e15dbdbe..7345a048a4128b 100644
--- a/Doc/c-api/hash.rst
+++ b/Doc/c-api/hash.rst
@@ -29,6 +29,12 @@ See also the :c:member:`PyTypeObject.tp_hash` member and :ref:`numeric-hash`.
.. 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.
diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst
index 1054b38cb92f7d..6e48644c8fef8b 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.
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index 9e118d4f36145f..36a4976010bde6 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.
@@ -418,12 +453,120 @@ Initializing and finalizing the interpreter
.. 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 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 argument 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
+ ``Py_InspectFlag`` is not set. If ``Py_InspectFlag`` is set, execution will
+ drop into the interactive Python prompt, at which point a second otherwise
+ unhandled :exc:`SystemExit` will still exit the process, while any other
+ means of exiting will set the return value as described above.
+
+ 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), or ``1`` if the interpreter exits due to an exception. If an
+ otherwise unhandled :exc:`SystemExit` is raised, the function will immediately
+ exit the process instead of returning ``1``.
+
+ 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: returning ``0``
+ if the session terminates without raising an unhandled exception, exiting
+ immediately for an unhandled :exc:`SystemExit`, and returning ``1`` for
+ any other unhandled exception.
+
+ This function always finalizes the Python interpreter regardless of whether
+ it returns a value or immediately exits the process due to an unhandled
+ :exc:`SystemExit` exception.
+
+ 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 +594,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 +624,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 +634,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 +648,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 +680,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 +836,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 +872,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 +898,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
@@ -1195,6 +1341,9 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
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 +1355,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`.
@@ -1296,6 +1445,17 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
.. versionadded:: 3.8
+
+.. c:function:: PyObject* PyUnstable_InterpreterState_GetMainModule(PyInterpreterState *interp)
+
+ Return a :term:`strong reference` to the ``__main__`` :ref:`module object `
+ for the given interpreter.
+
+ The caller must hold the GIL.
+
+ .. versionadded:: 3.13
+
+
.. c:type:: PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag)
Type of a frame evaluation function.
@@ -1548,7 +1708,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
@@ -2152,3 +2316,145 @@ 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 avoid deadlocks by implicitly suspending active critical
+sections and releasing the locks during calls to :c:func:`PyEval_SaveThread`.
+When :c:func:`PyEval_RestoreThread` is called, the most recent critical section
+is resumed, and its locks reacquired. This means the critical section API
+provides weaker guarantees than traditional locks -- they are useful because
+their behavior is similar to the :term:`GIL`.
+
+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
diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst
index 5195f6cccfe9df..612aa2aa711253 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.
@@ -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.
@@ -1348,14 +1348,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 +1584,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()
================
diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst
index 8ef463e3f88ca8..c4b2c7898dd11b 100644
--- a/Doc/c-api/intro.rst
+++ b/Doc/c-api/intro.rst
@@ -138,7 +138,7 @@ complete listing.
.. c:macro:: Py_ALWAYS_INLINE
Ask the compiler to always inline a static inline function. The compiler can
- ignore it and decides to not inline the function.
+ ignore it and decide to not inline the function.
It can be used to inline performance critical static inline functions when
building Python in debug mode with function inlining disabled. For example,
diff --git a/Doc/c-api/list.rst b/Doc/c-api/list.rst
index 53eb54d3e1021a..758415a76e5cb4 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)
diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst
index 522c028cfb8d40..1f899b1df196f2 100644
--- a/Doc/c-api/long.rst
+++ b/Doc/c-api/long.rst
@@ -139,7 +139,6 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
.. versionadded:: 3.13
-.. XXX alias PyLong_AS_LONG (for now)
.. c:function:: long PyLong_AsLong(PyObject *obj)
.. index::
@@ -161,6 +160,16 @@ 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)
+
+ A :term:`soft deprecated` alias.
+ Exactly equivalent to the preferred ``PyLong_AsLong``. In particular,
+ it can fail with :exc:`OverflowError` or another exception.
+
+ .. deprecated:: 3.14
+ The function is soft deprecated.
.. c:function:: int PyLong_AsInt(PyObject *obj)
@@ -405,14 +414,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 +454,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 +472,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 +494,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 +512,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 +538,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 +548,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/marshal.rst b/Doc/c-api/marshal.rst
index 489f1580a414b2..b9085ad3ec361d 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).
diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst
index 9da09a21607f61..f7618a025ba3d8 100644
--- a/Doc/c-api/memory.rst
+++ b/Doc/c-api/memory.rst
@@ -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:`here `.
+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
====================
@@ -299,6 +307,8 @@ versions and is therefore deprecated in extension modules.
* ``PyMem_DEL(ptr)``
+.. _objectinterface:
+
Object allocators
=================
diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst
index 6fe1ce9e994832..01a8e44828b191 100644
--- a/Doc/c-api/module.rst
+++ b/Doc/c-api/module.rst
@@ -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)
@@ -75,8 +78,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
@@ -106,8 +110,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
@@ -265,6 +269,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`
@@ -338,7 +344,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.
@@ -373,7 +380,8 @@ 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.
@@ -407,7 +415,7 @@ The available slot types are:
in one module definition.
If ``Py_mod_multiple_interpreters`` is not specified, the import
- machinery defaults to ``Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED``.
+ machinery defaults to ``Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED``.
.. versionadded:: 3.12
@@ -415,6 +423,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 +437,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 +471,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`
@@ -511,9 +523,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 +537,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,6 +556,14 @@ 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
@@ -601,15 +622,23 @@ state:
.. 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 +646,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 +659,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 +672,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 +711,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 763ec8ef761e4e..0c288819eb2bb9 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,10 +121,10 @@ 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
@@ -133,7 +133,7 @@ Managing the Monitoring State
Monitoring states can be managed with the help of monitoring scopes. A scope
would typically correspond to a python function.
-.. :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,64 @@ 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 `.
+
+ .. versionadded:: 3.13
-.. :c:function:: int PyMonitoring_ExitScope(void)
+ .. deprecated:: 3.13.3
- Exit the last scope that was entered with ``PyMonitoring_EnterScope``.
+ This function is :term:`soft deprecated`.
diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst
index 13d3c5af956905..ad8b5935258fa7 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 ba454db9117504..8bb392af01fcd2 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,7 +66,7 @@ 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
@@ -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)
@@ -351,14 +368,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 +387,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 +493,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 +517,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
diff --git a/Doc/c-api/refcounting.rst b/Doc/c-api/refcounting.rst
index bf50107347e0e7..d75dad737bc992 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::
diff --git a/Doc/c-api/reflection.rst b/Doc/c-api/reflection.rst
index 4b1c4770848a30..038e6977104560 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/slice.rst b/Doc/c-api/slice.rst
index 27a1757c745d8b..c6d761fe7fd1c9 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 5b9e43874c7f2b..124e58cf950b7a 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 f9461ab01f6049..a838434ca8125d 100644
--- a/Doc/c-api/structures.rst
+++ b/Doc/c-api/structures.rst
@@ -63,6 +63,11 @@ under :ref:`reference counting `.
See documentation of :c:type:`PyVarObject` above.
+.. c:var:: PyTypeObject PyBaseObject_Type
+
+ The base class of all other objects, the same as :class:`object` in Python.
+
+
.. c:function:: int Py_Is(PyObject *x, PyObject *y)
Test if the *x* object is the *y* object, the same as ``x is y`` in Python.
diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst
index d6fca1a0b0a219..c688afdca8231d 100644
--- a/Doc/c-api/sys.rst
+++ b/Doc/c-api/sys.rst
@@ -426,3 +426,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 5cfdef71b3e191..7032cc48aa6913 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 0d68a360f347f8..2944b8d342c9a8 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`` and 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)
@@ -135,6 +139,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 +149,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 +161,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 +208,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)
diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst
index 0cae5c09505ebe..be87b689fa1c22 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
@@ -140,7 +144,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.
@@ -174,29 +178,30 @@ Type Objects
.. 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
@@ -410,6 +415,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
@@ -478,19 +486,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 +518,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/typeobj.rst b/Doc/c-api/typeobj.rst
index a6a2c437ea4e16..93c377c54bc73b 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
@@ -355,7 +355,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 +473,7 @@ PyTypeObject Definition
-----------------------
The structure definition for :c:type:`PyTypeObject` can be found in
-:file:`Include/object.h`. For convenience of reference, this repeats the
+:file:`Include/cpython/object.h`. For convenience of reference, this repeats the
definition found there:
.. XXX Drop this?
@@ -537,6 +537,9 @@ PyVarObject Slots
initialized to zero. For :ref:`dynamically allocated type objects
`, this field has a special internal meaning.
+ This field should be accessed using the :c:func:`Py_SIZE()` and
+ :c:func:`Py_SET_SIZE()` macros.
+
**Inheritance:**
This field is not inherited by subtypes.
@@ -567,12 +570,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,47 +590,86 @@ and :c:data:`PyType_Type` effectively act as defaults.)
.. c:member:: Py_ssize_t PyTypeObject.tp_basicsize
- Py_ssize_t PyTypeObject.tp_itemsize
+ Py_ssize_t PyTypeObject.tp_itemsize
These fields allow calculating the size in bytes of instances of the type.
There are two kinds of types: types with fixed-length instances have a zero
- :c:member:`~PyTypeObject.tp_itemsize` field, types with variable-length instances have a non-zero
- :c:member:`~PyTypeObject.tp_itemsize` field. For a type with fixed-length instances, all
- instances have the same size, given in :c:member:`~PyTypeObject.tp_basicsize`.
+ :c:member:`!tp_itemsize` field, types with variable-length instances have a non-zero
+ :c:member:`!tp_itemsize` field. For a type with fixed-length instances, all
+ instances have the same size, given in :c:member:`!tp_basicsize`.
+ (Exceptions to this rule can be made using
+ :c:func:`PyUnstable_Object_GC_NewWithExtraData`.)
For a type with variable-length instances, the instances must have an
- :c:member:`~PyVarObject.ob_size` field, and the instance size is :c:member:`~PyTypeObject.tp_basicsize` plus N
- times :c:member:`~PyTypeObject.tp_itemsize`, where N is the "length" of the object. The value of
- N is typically stored in the instance's :c:member:`~PyVarObject.ob_size` field. There are
- exceptions: for example, ints use a negative :c:member:`~PyVarObject.ob_size` to indicate a
- negative number, and N is ``abs(ob_size)`` there. Also, the presence of an
- :c:member:`~PyVarObject.ob_size` field in the instance layout doesn't mean that the instance
- structure is variable-length (for example, the structure for the list type has
- fixed-length instances, yet those instances have a meaningful :c:member:`~PyVarObject.ob_size`
- field).
-
- The basic size includes the fields in the instance declared by the macro
- :c:macro:`PyObject_HEAD` or :c:macro:`PyObject_VAR_HEAD` (whichever is used to
- declare the instance struct) and this in turn includes the :c:member:`~PyObject._ob_prev` and
- :c:member:`~PyObject._ob_next` fields if they are present. This means that the only correct
- way to get an initializer for the :c:member:`~PyTypeObject.tp_basicsize` is to use the
- ``sizeof`` operator on the struct used to declare the instance layout.
- The basic size does not include the GC header size.
+ :c:member:`~PyVarObject.ob_size` field, and the instance size is
+ :c:member:`!tp_basicsize` plus N times :c:member:`!tp_itemsize`,
+ where N is the "length" of the object.
+
+ Functions like :c:func:`PyObject_NewVar` will take the value of N as an
+ argument, and store in the instance's :c:member:`~PyVarObject.ob_size` field.
+ Note that the :c:member:`~PyVarObject.ob_size` field may later be used for
+ other purposes. For example, :py:type:`int` instances use the bits of
+ :c:member:`~PyVarObject.ob_size` in an implementation-defined
+ way; the underlying storage and its size should be accessed using
+ :c:func:`PyLong_Export`.
+
+ .. note::
+
+ The :c:member:`~PyVarObject.ob_size` field should be accessed using
+ the :c:func:`Py_SIZE()` and :c:func:`Py_SET_SIZE()` macros.
- A note about alignment: if the variable items require a particular alignment,
- this should be taken care of by the value of :c:member:`~PyTypeObject.tp_basicsize`. Example:
- suppose a type implements an array of ``double``. :c:member:`~PyTypeObject.tp_itemsize` is
- ``sizeof(double)``. It is the programmer's responsibility that
- :c:member:`~PyTypeObject.tp_basicsize` is a multiple of ``sizeof(double)`` (assuming this is the
- alignment requirement for ``double``).
+ Also, the presence of an :c:member:`~PyVarObject.ob_size` field in the
+ instance layout doesn't mean that the instance structure is variable-length.
+ For example, the :py:type:`list` type has fixed-length instances, yet those
+ instances have a :c:member:`~PyVarObject.ob_size` field.
+ (As with :py:type:`int`, avoid reading lists' :c:member:`!ob_size` directly.
+ Call :c:func:`PyList_Size` instead.)
- For any type with variable-length instances, this field must not be ``NULL``.
+ The :c:member:`!tp_basicsize` includes size needed for data of the type's
+ :c:member:`~PyTypeObject.tp_base`, plus any extra data needed
+ by each instance.
+
+ The correct way to set :c:member:`!tp_basicsize` is to use the
+ ``sizeof`` operator on the struct used to declare the instance layout.
+ This struct must include the struct used to declare the base type.
+ In other words, :c:member:`!tp_basicsize` must be greater than or equal
+ to the base's :c:member:`!tp_basicsize`.
+
+ Since every type is a subtype of :py:type:`object`, this struct must
+ include :c:type:`PyObject` or :c:type:`PyVarObject` (depending on
+ whether :c:member:`~PyVarObject.ob_size` should be included). These are
+ usually defined by the macro :c:macro:`PyObject_HEAD` or
+ :c:macro:`PyObject_VAR_HEAD`, respectively.
+
+ The basic size does not include the GC header size, as that header is not
+ part of :c:macro:`PyObject_HEAD`.
+
+ For cases where struct used to declare the base type is unknown,
+ see :c:member:`PyType_Spec.basicsize` and :c:func:`PyType_FromMetaclass`.
+
+ Notes about alignment:
+
+ - :c:member:`!tp_basicsize` must be a multiple of ``_Alignof(PyObject)``.
+ When using ``sizeof`` on a ``struct`` that includes
+ :c:macro:`PyObject_HEAD`, as recommended, the compiler ensures this.
+ When not using a C ``struct``, or when using compiler
+ extensions like ``__attribute__((packed))``, it is up to you.
+ - If the variable items require a particular alignment,
+ :c:member:`!tp_basicsize` and :c:member:`!tp_itemsize` must each be a
+ multiple of that alignment.
+ For example, if a type's variable part stores a ``double``, it is
+ your responsibility that both fields are a multiple of
+ ``_Alignof(double)``.
**Inheritance:**
- These fields are inherited separately by subtypes. If the base type has a
- non-zero :c:member:`~PyTypeObject.tp_itemsize`, it is generally not safe to set
+ These fields are inherited separately by subtypes.
+ (That is, if the field is set to zero, :c:func:`PyType_Ready` will copy
+ the value from the base type, indicating that the instances do not
+ need additional storage.)
+
+ If the base type has a non-zero :c:member:`~PyTypeObject.tp_itemsize`, it is generally not safe to set
:c:member:`~PyTypeObject.tp_itemsize` to a different non-zero value in a subtype (though this
depends on the implementation of the base type).
@@ -682,6 +724,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:**
@@ -1131,7 +1186,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 `~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.
@@ -1328,15 +1383,15 @@ 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:member:: const char* PyTypeObject.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:**
@@ -1592,7 +1647,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,7 +1659,7 @@ 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.
@@ -1816,7 +1871,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:**
@@ -2036,7 +2091,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
@@ -2098,28 +2153,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 +2241,7 @@ This is done by filling a :c:type:`PyType_Spec` structure and calling
.. _number-structs:
Number Object Structures
-========================
+------------------------
.. sectionauthor:: Amaury Forgeot d'Arc
@@ -2313,7 +2355,7 @@ Number Object Structures
.. _mapping-structs:
Mapping Object Structures
-=========================
+-------------------------
.. sectionauthor:: Amaury Forgeot d'Arc
@@ -2350,7 +2392,7 @@ Mapping Object Structures
.. _sequence-structs:
Sequence Object Structures
-==========================
+--------------------------
.. sectionauthor:: Amaury Forgeot d'Arc
@@ -2430,7 +2472,7 @@ Sequence Object Structures
.. _buffer-structs:
Buffer Object Structures
-========================
+------------------------
.. sectionauthor:: Greg J. Stein
.. sectionauthor:: Benjamin Peterson
@@ -2525,7 +2567,7 @@ Buffer Object Structures
Async Object Structures
-=======================
+-----------------------
.. sectionauthor:: Yury Selivanov
@@ -2593,7 +2635,7 @@ Async Object Structures
.. _slot-typedefs:
Slot Type typedefs
-==================
+------------------
.. c:type:: PyObject *(*allocfunc)(PyTypeObject *cls, Py_ssize_t nitems)
@@ -2616,7 +2658,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 +2744,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 7320d035bab513..7baf8de10c8175 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:
@@ -317,7 +318,7 @@ These APIs can be used to work with surrogates:
.. 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].
@@ -338,6 +339,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 +595,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 +621,21 @@ APIs:
decref'ing the returned objects.
+.. 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
@@ -657,6 +679,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 +690,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 +700,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 +804,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 +830,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 +1036,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 +1051,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
@@ -1020,6 +1072,15 @@ 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
@@ -1309,6 +1370,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
@@ -1353,6 +1421,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 +1443,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 +1538,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 +1600,41 @@ 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.
+
+ .. impl-detail::
+
+ Strings interned this way are made :term:`immortal`.
+
+
diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst
index 67167444d0a685..1ef4181d52eb10 100644
--- a/Doc/c-api/veryhigh.rst
+++ b/Doc/c-api/veryhigh.rst
@@ -25,30 +25,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
@@ -372,8 +348,20 @@ the same library that the Python runtime is using.
.. 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.
-.. c:var:: int CO_FUTURE_DIVISION
+ .. c:var:: int CO_FUTURE_DIVISION
- This bit can be set in *flags* to cause division operator ``/`` to be
- interpreted as "true division" according to :pep:`238`.
+ This bit can be set in *flags* to cause division operator ``/`` to be
+ interpreted as "true division" according to :pep:`238`.
diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst
index 038f54a9751fd1..8f233e16fb17cf 100644
--- a/Doc/c-api/weakref.rst
+++ b/Doc/c-api/weakref.rst
@@ -35,7 +35,7 @@ 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
+ weakly referenceable object, or if *callback* is not callable, ``None``, or
``NULL``, this will return ``NULL`` and raise :exc:`TypeError`.
@@ -47,7 +47,7 @@ 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,
+ is not a weakly referenceable object, or if *callback* is not callable,
``None``, or ``NULL``, this will return ``NULL`` and raise :exc:`TypeError`.
@@ -96,3 +96,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 86371d17ae742a..022553b5ff5580 100644
--- a/Doc/conf.py
+++ b/Doc/conf.py
@@ -8,21 +8,31 @@
import os
import sys
-import time
+from importlib import import_module
+from importlib.util import find_spec
+
+# Make our custom extensions available to Sphinx
sys.path.append(os.path.abspath('tools/extensions'))
sys.path.append(os.path.abspath('includes'))
+# Python specific content from Doc/Tools/extensions/pyspecific.py
from pyspecific import SOURCE_URI
# 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 +40,17 @@
]
# 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 = (
+ 'notfound.extension',
+ 'sphinxext.opengraph',
+)
+for optional_ext in _OPTIONAL_EXTENSIONS:
+ try:
+ if find_spec(optional_ext) is not None:
+ extensions.append(optional_ext)
+ except (ImportError, ValueError):
+ pass
+del _OPTIONAL_EXTENSIONS
doctest_global_setup = '''
try:
@@ -50,7 +58,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,12 +68,12 @@
# General substitutions.
project = 'Python'
-copyright = f"2001-{time.strftime('%Y')}, Python Software Foundation"
+copyright = "2001-%Y, Python Software Foundation"
# 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 = import_module('patchlevel').get_version_info()
rst_epilog = f"""
.. |python_version_literal| replace:: ``Python {version}``
@@ -73,24 +81,25 @@
.. |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 +140,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 +151,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'),
@@ -182,6 +196,7 @@
('envvar', 'LC_TIME'),
('envvar', 'LINES'),
('envvar', 'LOGNAME'),
+ ('envvar', 'MANPAGER'),
('envvar', 'PAGER'),
('envvar', 'PATH'),
('envvar', 'PATHEXT'),
@@ -242,6 +257,7 @@
('c:data', 'PyExc_OverflowError'),
('c:data', 'PyExc_PermissionError'),
('c:data', 'PyExc_ProcessLookupError'),
+ ('c:data', 'PyExc_PythonFinalizationError'),
('c:data', 'PyExc_RecursionError'),
('c:data', 'PyExc_ReferenceError'),
('c:data', 'PyExc_RuntimeError'),
@@ -272,6 +288,9 @@
('c:data', 'PyExc_UnicodeWarning'),
('c:data', 'PyExc_UserWarning'),
('c:data', 'PyExc_Warning'),
+ # Undocumented public C macros
+ ('c:macro', 'Py_BUILD_ASSERT'),
+ ('c:macro', 'Py_BUILD_ASSERT_EXPR'),
# Do not error nit-picky mode builds when _SubParsersAction.add_parser cannot
# be resolved, as the method is currently undocumented. For context, see
# https://github.com/python/cpython/pull/103289.
@@ -296,7 +315,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 +325,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,17 +359,21 @@
# 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"),
}
# 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']
# Custom sidebar templates, filenames relative to this file.
@@ -374,6 +402,8 @@
# Split the index
html_split_index = True
+# Split pot files one per reST file
+gettext_compact = False
# Options for LaTeX output
# ------------------------
@@ -391,8 +421,8 @@
\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',
}
@@ -401,30 +431,70 @@
# (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', _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',
+ ),
]
# 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', '', _stdauthor, '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']
@@ -435,6 +505,10 @@
epub_author = 'Python Documentation Authors'
epub_publisher = 'Python Software Foundation'
+# index pages are not valid xhtml
+# https://github.com/sphinx-doc/sphinx/issues/12359
+epub_use_index = False
+
# Options for the coverage checker
# --------------------------------
@@ -448,8 +522,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 +539,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 +555,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/.+',
@@ -524,26 +601,34 @@
# 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"),
"pypi": ("https://pypi.org/project/%s/", "%s"),
"source": (SOURCE_URI, "%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 sphinxext-opengraph
+# -------------------------------
+
+ogp_canonical_url = 'https://docs.python.org/3/'
ogp_site_name = 'Python documentation'
-ogp_image = '_static/og-image.png'
+ogp_social_cards = { # Used when matplotlib is installed
+ 'image': '_static/og-image.png',
+ 'line_color': '#3776ab',
+}
ogp_custom_meta_tags = [
- '',
- '',
- '',
+ '',
]
+if 'create-social-cards' not in tags: # noqa: F821
+ # Define a static preview image when not creating social cards
+ ogp_image = '_static/og-image.png'
+ ogp_custom_meta_tags += [
+ '',
+ '',
+ ]
diff --git a/Doc/constraints.txt b/Doc/constraints.txt
index 147de1271eb2b7..29cd4be1d3c8db 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 24ceacb0076b5e..b57f4b09a5dcb6 100644
--- a/Doc/contents.rst
+++ b/Doc/contents.rst
@@ -14,6 +14,7 @@
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 00000000000000..617006a6489605
--- /dev/null
+++ b/Doc/data/python3.13.abi
@@ -0,0 +1,29418 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat
index 62a96146d605ff..964914aa714f09 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:
@@ -1269,7 +1303,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 +1463,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 +1473,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 +1836,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 +1976,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:
@@ -2382,7 +2419,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 +2486,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 +2539,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 +2622,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 +2641,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 +2756,12 @@ PyUnicode_FromFormatV:PyObject*::+1:
PyUnicode_FromFormatV:const char*:format::
PyUnicode_FromFormatV:va_list:args::
+PyUnicode_FromOrdinal:PyObject*::+1:
+PyUnicode_FromOrdinal:int:ordinal::
+
+PyUnicode_GetDefaultEncoding:const char*:::
+PyUnicode_GetDefaultEncoding::void::
+
PyUnicode_GetLength:Py_ssize_t:::
PyUnicode_GetLength:PyObject*:unicode:0:
@@ -2825,13 +2888,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 76a035f194d911..75bc5ea94567eb 100644
--- a/Doc/data/stable_abi.dat
+++ b/Doc/data/stable_abi.dat
@@ -1,888 +1,887 @@
role,name,added,ifdef_note,struct_abi_kind
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,,
+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,,
+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,,
+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,,
+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,,
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,,
type,Py_buffer,3.11,,full-abi
type,Py_intptr_t,3.2,,
type,Py_ssize_t,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 00000000000000..d16da66c29abe7
--- /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 00000000000000..fcb703e66fe9eb
--- /dev/null
+++ b/Doc/deprecations/c-api-pending-removal-in-3.15.rst
@@ -0,0 +1,27 @@
+Pending Removal in Python 3.15
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* The bundled copy of ``libmpdecimal``.
+* 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-future.rst b/Doc/deprecations/c-api-pending-removal-in-future.rst
new file mode 100644
index 00000000000000..0c3ae52b87ff74
--- /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 00000000000000..5aa7062aca2ca6
--- /dev/null
+++ b/Doc/deprecations/index.rst
@@ -0,0 +1,19 @@
+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-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 00000000000000..89790497816e83
--- /dev/null
+++ b/Doc/deprecations/pending-removal-in-3.13.rst
@@ -0,0 +1,52 @@
+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`)
+* :mod:`importlib.resources` deprecated methods:
+
+ * ``contents()``
+ * ``is_resource()``
+ * ``open_binary()``
+ * ``open_text()``
+ * ``path()``
+ * ``read_binary()``
+ * ``read_text()``
+
+ Use :func:`importlib.resources.files` instead. Refer to `importlib-resources: Migrating from Legacy
+ `_ (:gh:`106531`)
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 00000000000000..15606f61cf8b0c
--- /dev/null
+++ b/Doc/deprecations/pending-removal-in-3.14.rst
@@ -0,0 +1,105 @@
+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:`collections.abc`: Deprecated :class:`~collections.abc.ByteString`.
+ Prefer :class:`!Sequence` or :class:`~collections.abc.Buffer`.
+ For use in typing, prefer a union, like ``bytes | bytearray``,
+ or :class:`collections.abc.Buffer`.
+ (Contributed by Shantanu Jain in :gh:`91896`.)
+
+* :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:`typing`: :class:`~typing.ByteString`, deprecated since Python 3.9,
+ now causes a :exc:`DeprecationWarning` to be emitted when it is used.
+
+* :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 00000000000000..b607703b30bfff
--- /dev/null
+++ b/Doc/deprecations/pending-removal-in-3.15.rst
@@ -0,0 +1,98 @@
+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.
+
+* :class:`locale`:
+
+ * The :func:`~locale.getdefaultlocale` function
+ has been deprecated since Python 3.11.
+ Its removal was originally planned for Python 3.13 (:gh:`90817`),
+ but has been postponed to Python 3.15.
+ Use :func:`~locale.getlocale`, :func:`~locale.setlocale`,
+ and :func:`~locale.getencoding` instead.
+ (Contributed by Hugo van Kemenade in :gh:`111187`.)
+
+* :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.
+
+ * The :func:`typing.no_type_check_decorator` decorator function
+ has been deprecated since Python 3.13.
+ After eight years in the :mod:`typing` module,
+ it has yet to be supported by any major type checker.
+
+* :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 00000000000000..6f6954b783a1ae
--- /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-future.rst b/Doc/deprecations/pending-removal-in-future.rst
new file mode 100644
index 00000000000000..a865e6ce585df3
--- /dev/null
+++ b/Doc/deprecations/pending-removal-in-future.rst
@@ -0,0 +1,149 @@
+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`:
+
+ * ``bool(NotImplemented)``.
+ * 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/embedding.rst b/Doc/extending/embedding.rst
index 20397dc5add5db..b777862da79f14 100644
--- a/Doc/extending/embedding.rst
+++ b/Doc/extending/embedding.rst
@@ -196,8 +196,8 @@ interesting part with respect to embedding Python starts with ::
After initializing the interpreter, the script is loaded using
:c:func:`PyImport_Import`. This routine needs a Python string as its argument,
-which is constructed using the :c:func:`PyUnicode_FromString` data conversion
-routine. ::
+which is constructed using the :c:func:`PyUnicode_DecodeFSDefault` data
+conversion routine. ::
pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */
diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst
index b70e1b1fe57e67..b0493bed75b151 100644
--- a/Doc/extending/extending.rst
+++ b/Doc/extending/extending.rst
@@ -868,7 +868,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.
diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst
index 473a418809cff1..7f57a3a6aac0ed 100644
--- a/Doc/extending/newtypes.rst
+++ b/Doc/extending/newtypes.rst
@@ -296,7 +296,7 @@ An interesting advantage of using the :c:member:`~PyTypeObject.tp_members` table
descriptors that are used at runtime is that any attribute defined this way can
have an associated doc string simply by providing the text in the table. An
application can use the introspection API to retrieve the descriptor from the
-class object, and get the doc string using its :attr:`!__doc__` attribute.
+class object, and get the doc string using its :attr:`~type.__doc__` attribute.
As with the :c:member:`~PyTypeObject.tp_methods` table, a sentinel entry with a :c:member:`~PyMethodDef.ml_name` value
of ``NULL`` is required.
@@ -545,7 +545,7 @@ performance-critical objects (such as numbers).
.. seealso::
Documentation for the :mod:`weakref` module.
-For an object to be weakly referencable, the extension type must set the
+For an object to be weakly referenceable, the extension type must set the
``Py_TPFLAGS_MANAGED_WEAKREF`` bit of the :c:member:`~PyTypeObject.tp_flags`
field. The legacy :c:member:`~PyTypeObject.tp_weaklistoffset` field should
be left as zero.
diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst
index 7eba9759119b3b..bcf938f117d148 100644
--- a/Doc/extending/newtypes_tutorial.rst
+++ b/Doc/extending/newtypes_tutorial.rst
@@ -144,7 +144,7 @@ only used for variable-sized objects and should otherwise be zero.
If you want your type to be subclassable from Python, and your type has the same
:c:member:`~PyTypeObject.tp_basicsize` as its base type, you may have problems with multiple
inheritance. A Python subclass of your type will have to list your type first
- in its :attr:`~class.__bases__`, or else it will not be able to call your type's
+ in its :attr:`~type.__bases__`, or else it will not be able to call your type's
:meth:`~object.__new__` method without getting an error. You can avoid this problem by
ensuring that your type has a larger value for :c:member:`~PyTypeObject.tp_basicsize` than its
base type does. Most of the time, this will be true anyway, because either your
@@ -447,7 +447,7 @@ Further, the attributes can be deleted, setting the C pointers to ``NULL``. Eve
though we can make sure the members are initialized to non-``NULL`` values, the
members can be set to ``NULL`` if the attributes are deleted.
-We define a single method, :meth:`!Custom.name()`, that outputs the objects name as the
+We define a single method, :meth:`!Custom.name`, that outputs the objects name as the
concatenation of the first and last names. ::
static PyObject *
diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst
index c8beb64e39bc1a..e2710fab9cf800 100644
--- a/Doc/faq/design.rst
+++ b/Doc/faq/design.rst
@@ -70,7 +70,7 @@ operations. This means that as far as floating-point operations are concerned,
Python behaves like many popular languages including C and Java.
Many numbers that can be written easily in decimal notation cannot be expressed
-exactly in binary floating-point. For example, after::
+exactly in binary floating point. For example, after::
>>> x = 1.2
@@ -87,7 +87,7 @@ which is exactly::
The typical precision of 53 bits provides Python floats with 15--16
decimal digits of accuracy.
-For a fuller explanation, please see the :ref:`floating point arithmetic
+For a fuller explanation, please see the :ref:`floating-point arithmetic
` chapter in the Python tutorial.
@@ -328,7 +328,7 @@ Can Python be compiled to machine code, C or some other language?
-----------------------------------------------------------------
`Cython `_ compiles a modified version of Python with
-optional annotations into C extensions. `Nuitka `_ is
+optional annotations into C extensions. `Nuitka `_ is
an up-and-coming compiler of Python into C++ code, aiming to support the full
Python language.
@@ -345,7 +345,7 @@ to perform a garbage collection, obtain debugging statistics, and tune the
collector's parameters.
Other implementations (such as `Jython `_ or
-`PyPy `_), however, can rely on a different mechanism
+`PyPy `_), however, can rely on a different mechanism
such as a full-blown garbage collector. This difference can cause some
subtle porting problems if your Python code depends on the behavior of the
reference counting implementation.
diff --git a/Doc/faq/extending.rst b/Doc/faq/extending.rst
index 1cff2c4091df06..3147fda7c37124 100644
--- a/Doc/faq/extending.rst
+++ b/Doc/faq/extending.rst
@@ -246,13 +246,12 @@ Then, when you run GDB:
I want to compile a Python module on my Linux system, but some files are missing. Why?
--------------------------------------------------------------------------------------
-Most packaged versions of Python don't include the
-:file:`/usr/lib/python2.{x}/config/` directory, which contains various files
+Most packaged versions of Python omit some files
required for compiling Python extensions.
-For Red Hat, install the python-devel RPM to get the necessary files.
+For Red Hat, install the python3-devel RPM to get the necessary files.
-For Debian, run ``apt-get install python-dev``.
+For Debian, run ``apt-get install python3-dev``.
How do I tell "incomplete input" from "invalid input"?
------------------------------------------------------
diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst
index ec7c2897594999..2a55f6b6fb6181 100644
--- a/Doc/faq/general.rst
+++ b/Doc/faq/general.rst
@@ -122,6 +122,8 @@ available. Consult `the Python Package Index `_ to
find packages of interest to you.
+.. _faq-version-numbering-scheme:
+
How does the Python version numbering scheme work?
--------------------------------------------------
@@ -183,8 +185,6 @@ information on getting the source code and compiling it.
How do I get documentation on Python?
-------------------------------------
-.. XXX mention py3k
-
The standard documentation for the current stable version of Python is available
at https://docs.python.org/3/. PDF, plain text, and downloadable HTML versions are
also available at https://docs.python.org/3/download.html.
@@ -309,10 +309,10 @@ guaranteed that interfaces will remain the same throughout a series of bugfix
releases.
The latest stable releases can always be found on the `Python download page
-`_. There are two production-ready versions
-of Python: 2.x and 3.x. The recommended version is 3.x, which is supported by
-most widely used libraries. Although 2.x is still widely used, `it is not
-maintained anymore `_.
+`_.
+Python 3.x is the recommended version and supported by most widely used libraries.
+Python 2.x :pep:`is not maintained anymore <373>`.
+
How many people are using Python?
---------------------------------
diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst
index b959cd73921428..522923572bfbbf 100644
--- a/Doc/faq/library.rst
+++ b/Doc/faq/library.rst
@@ -796,12 +796,12 @@ is simple::
import random
random.random()
-This returns a random floating point number in the range [0, 1).
+This returns a random floating-point number in the range [0, 1).
There are also many other specialized generators in this module, such as:
* ``randrange(a, b)`` chooses an integer in the range [a, b).
-* ``uniform(a, b)`` chooses a floating point number in the range [a, b).
+* ``uniform(a, b)`` chooses a floating-point number in the range [a, b).
* ``normalvariate(mean, sdev)`` samples the normal (Gaussian) distribution.
Some higher-level functions operate on sequences directly, such as:
diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst
index 0a88c5f6384f2b..9f9e4fab685b19 100644
--- a/Doc/faq/programming.rst
+++ b/Doc/faq/programming.rst
@@ -869,7 +869,7 @@ How do I convert a string to a number?
--------------------------------------
For integers, use the built-in :func:`int` type constructor, e.g. ``int('144')
-== 144``. Similarly, :func:`float` converts to floating-point,
+== 144``. Similarly, :func:`float` converts to a floating-point number,
e.g. ``float('144') == 144.0``.
By default, these interpret the number as decimal, so that ``int('0144') ==
@@ -986,8 +986,8 @@ There are various techniques.
f()
-Is there an equivalent to Perl's chomp() for removing trailing newlines from strings?
--------------------------------------------------------------------------------------
+Is there an equivalent to Perl's ``chomp()`` for removing trailing newlines from strings?
+-----------------------------------------------------------------------------------------
You can use ``S.rstrip("\r\n")`` to remove all occurrences of any line
terminator from the end of the string ``S`` without removing other trailing
@@ -1005,23 +1005,23 @@ Since this is typically only desired when reading text one line at a time, using
``S.rstrip()`` this way works well.
-Is there a scanf() or sscanf() equivalent?
-------------------------------------------
+Is there a ``scanf()`` or ``sscanf()`` equivalent?
+--------------------------------------------------
Not as such.
For simple input parsing, the easiest approach is usually to split the line into
whitespace-delimited words using the :meth:`~str.split` method of string objects
and then convert decimal strings to numeric values using :func:`int` or
-:func:`float`. :meth:`!split()` supports an optional "sep" parameter which is useful
+:func:`float`. :meth:`!split` supports an optional "sep" parameter which is useful
if the line uses something other than whitespace as a separator.
For more complicated input parsing, regular expressions are more powerful
than C's ``sscanf`` and better suited for the task.
-What does 'UnicodeDecodeError' or 'UnicodeEncodeError' error mean?
--------------------------------------------------------------------
+What does ``UnicodeDecodeError`` or ``UnicodeEncodeError`` error mean?
+----------------------------------------------------------------------
See the :ref:`unicode-howto`.
@@ -1036,7 +1036,7 @@ A raw string ending with an odd number of backslashes will escape the string's q
>>> r'C:\this\will\not\work\'
File "", line 1
r'C:\this\will\not\work\'
- ^
+ ^
SyntaxError: unterminated string literal (detected at line 1)
There are several workarounds for this. One is to use regular strings and double
@@ -1613,9 +1613,16 @@ method too, and it must do so carefully. The basic implementation of
self.__dict__[name] = value
...
-Most :meth:`!__setattr__` implementations must modify
-:meth:`self.__dict__ ` to store
-local state for self without causing an infinite recursion.
+Many :meth:`~object.__setattr__` implementations call :meth:`!object.__setattr__` to set
+an attribute on self without causing infinite recursion::
+
+ class X:
+ def __setattr__(self, name, value):
+ # Custom logic here...
+ object.__setattr__(self, name, value)
+
+Alternatively, it is possible to set attributes by inserting
+entries into :attr:`self.__dict__ ` directly.
How do I call a method defined in a base class from a derived class that extends it?
@@ -1741,11 +1748,31 @@ but effective way to define class private variables. Any identifier of the form
is textually replaced with ``_classname__spam``, where ``classname`` is the
current class name with any leading underscores stripped.
-This doesn't guarantee privacy: an outside user can still deliberately access
-the "_classname__spam" attribute, and private values are visible in the object's
-``__dict__``. Many Python programmers never bother to use private variable
-names at all.
+The identifier can be used unchanged within the class, but to access it outside
+the class, the mangled name must be used:
+
+.. code-block:: python
+ class A:
+ def __one(self):
+ return 1
+ def two(self):
+ return 2 * self.__one()
+
+ class B(A):
+ def three(self):
+ return 3 * self._A__one()
+
+ four = 4 * A()._A__one()
+
+In particular, this does not guarantee privacy since an outside user can still
+deliberately access the private attribute; many Python programmers never bother
+to use private variable names at all.
+
+.. seealso::
+
+ The :ref:`private name mangling specifications `
+ for details and special cases.
My class defines __del__ but it is not called when I delete the object.
-----------------------------------------------------------------------
@@ -1841,15 +1868,15 @@ object identity is assured. Generally, there are three circumstances where
identity is guaranteed:
1) Assignments create new names but do not change object identity. After the
-assignment ``new = old``, it is guaranteed that ``new is old``.
+ assignment ``new = old``, it is guaranteed that ``new is old``.
2) Putting an object in a container that stores object references does not
-change object identity. After the list assignment ``s[0] = x``, it is
-guaranteed that ``s[0] is x``.
+ change object identity. After the list assignment ``s[0] = x``, it is
+ guaranteed that ``s[0] is x``.
3) If an object is a singleton, it means that only one instance of that object
-can exist. After the assignments ``a = None`` and ``b = None``, it is
-guaranteed that ``a is b`` because ``None`` is a singleton.
+ can exist. After the assignments ``a = None`` and ``b = None``, it is
+ guaranteed that ``a is b`` because ``None`` is a singleton.
In most other circumstances, identity tests are inadvisable and equality tests
are preferred. In particular, identity tests should not be used to check
@@ -1879,28 +1906,30 @@ In the standard library code, you will see several common patterns for
correctly using identity tests:
1) As recommended by :pep:`8`, an identity test is the preferred way to check
-for ``None``. This reads like plain English in code and avoids confusion with
-other objects that may have boolean values that evaluate to false.
+ for ``None``. This reads like plain English in code and avoids confusion
+ with other objects that may have boolean values that evaluate to false.
2) Detecting optional arguments can be tricky when ``None`` is a valid input
-value. In those situations, you can create a singleton sentinel object
-guaranteed to be distinct from other objects. For example, here is how
-to implement a method that behaves like :meth:`dict.pop`::
+ value. In those situations, you can create a singleton sentinel object
+ guaranteed to be distinct from other objects. For example, here is how
+ to implement a method that behaves like :meth:`dict.pop`:
+
+ .. code-block:: python
- _sentinel = object()
+ _sentinel = object()
- def pop(self, key, default=_sentinel):
- if key in self:
- value = self[key]
- del self[key]
- return value
- if default is _sentinel:
- raise KeyError(key)
- return default
+ def pop(self, key, default=_sentinel):
+ if key in self:
+ value = self[key]
+ del self[key]
+ return value
+ if default is _sentinel:
+ raise KeyError(key)
+ return default
3) Container implementations sometimes need to augment equality tests with
-identity tests. This prevents the code from being confused by objects such as
-``float('NaN')`` that are not equal to themselves.
+ identity tests. This prevents the code from being confused by objects
+ such as ``float('NaN')`` that are not equal to themselves.
For example, here is the implementation of
:meth:`!collections.abc.Sequence.__contains__`::
diff --git a/Doc/glossary.rst b/Doc/glossary.rst
index 2846f77feb112d..1ca9d0f5e7b407 100644
--- a/Doc/glossary.rst
+++ b/Doc/glossary.rst
@@ -110,7 +110,7 @@ Glossary
:keyword:`yield` expression.
Each :keyword:`yield` temporarily suspends processing, remembering the
- location execution state (including local variables and pending
+ execution state (including local variables and pending
try-statements). When the *asynchronous generator iterator* effectively
resumes with another awaitable returned by :meth:`~object.__anext__`, it
picks up where it left off. See :pep:`492` and :pep:`525`.
@@ -226,6 +226,28 @@ Glossary
A variable defined in a class and intended to be modified only at
class level (i.e., not in an instance of the class).
+ closure variable
+ A :term:`free variable` referenced from a :term:`nested scope` that is defined in an outer
+ scope rather than being resolved at runtime from the globals or builtin namespaces.
+ May be explicitly defined with the :keyword:`nonlocal` keyword to allow write access,
+ or implicitly defined if the variable is only being read.
+
+ For example, in the ``inner`` function in the following code, both ``x`` and ``print`` are
+ :term:`free variables `, but only ``x`` is a *closure variable*::
+
+ def outer():
+ x = 0
+ def inner():
+ nonlocal x
+ x += 1
+ print(x)
+ return inner
+
+ Due to the :attr:`codeobject.co_freevars` attribute (which, despite its name, only
+ includes the names of closure variables rather than listing all referenced free
+ variables), the more general :term:`free variable` term is sometimes used even
+ when the intended meaning is to refer specifically to closure variables.
+
complex number
An extension of the familiar real number system in which all numbers are
expressed as a sum of a real part and an imaginary part. Imaginary
@@ -238,19 +260,33 @@ Glossary
advanced mathematical feature. If you're not aware of a need for them,
it's almost certain you can safely ignore them.
+ context
+ This term has different meanings depending on where and how it is used.
+ Some common meanings:
+
+ * The temporary state or environment established by a :term:`context
+ manager` via a :keyword:`with` statement.
+ * The collection of keyÂvalue bindings associated with a particular
+ :class:`contextvars.Context` object and accessed via
+ :class:`~contextvars.ContextVar` objects. Also see :term:`context
+ variable`.
+ * A :class:`contextvars.Context` object. Also see :term:`current
+ context`.
+
+ context management protocol
+ The :meth:`~object.__enter__` and :meth:`~object.__exit__` methods called
+ by the :keyword:`with` statement. See :pep:`343`.
+
context manager
- An object which controls the environment seen in a :keyword:`with`
- statement by defining :meth:`~object.__enter__` and :meth:`~object.__exit__` methods.
- See :pep:`343`.
+ An object which implements the :term:`context management protocol` and
+ controls the environment seen in a :keyword:`with` statement. See
+ :pep:`343`.
context variable
- A variable which can have different values depending on its context.
- This is similar to Thread-Local Storage in which each execution
- thread may have a different value for a variable. However, with context
- variables, there may be several contexts in one execution thread and the
- main usage for context variables is to keep track of variables in
+ A variable whose value depends on which context is the :term:`current
+ context`. Values are accessed via :class:`contextvars.ContextVar`
+ objects. Context variables are primarily used to isolate state between
concurrent asynchronous tasks.
- See :mod:`contextvars`.
contiguous
.. index:: C-contiguous, Fortran contiguous
@@ -284,6 +320,14 @@ Glossary
is used when necessary to distinguish this implementation from others
such as Jython or IronPython.
+ current context
+ The :term:`context` (:class:`contextvars.Context` object) that is
+ currently used by :class:`~contextvars.ContextVar` objects to access (get
+ or set) the values of :term:`context variables `. Each
+ thread has its own current context. Frameworks for executing asynchronous
+ tasks (see :mod:`asyncio`) associate each task with a context which
+ becomes the current context whenever the task starts or resumes execution.
+
decorator
A function returning another function, usually applied as a function
transformation using the ``@wrapper`` syntax. Common examples for
@@ -342,7 +386,7 @@ Glossary
docstring
A string literal which appears as the first expression in a class,
function or module. While ignored when the suite is executed, it is
- recognized by the compiler and put into the :attr:`!__doc__` attribute
+ recognized by the compiler and put into the :attr:`~definition.__doc__` attribute
of the enclosing class, function or module. Since it is available via
introspection, it is the canonical place for documentation of the
object.
@@ -425,11 +469,11 @@ Glossary
An object that tries to find the :term:`loader` for a module that is
being imported.
- Since Python 3.3, there are two types of finder: :term:`meta path finders
+ There are two types of finder: :term:`meta path finders
` for use with :data:`sys.meta_path`, and :term:`path
entry finders ` for use with :data:`sys.path_hooks`.
- See :pep:`302`, :pep:`420` and :pep:`451` for much more detail.
+ See :ref:`finders-and-loaders` and :mod:`importlib` for much more detail.
floor division
Mathematical division that rounds down to nearest integer. The floor
@@ -438,6 +482,19 @@ Glossary
division. Note that ``(-11) // 4`` is ``-3`` because that is ``-2.75``
rounded *downward*. See :pep:`238`.
+ free threading
+ A threading model where multiple threads can run Python bytecode
+ simultaneously within the same interpreter. This is in contrast to
+ the :term:`global interpreter lock` which allows only one thread to
+ execute Python bytecode at a time. See :pep:`703`.
+
+ free variable
+ Formally, as defined in the :ref:`language execution model `, a free
+ variable is any variable used in a namespace which is not a local variable in that
+ namespace. See :term:`closure variable` for an example.
+ Pragmatically, due to the name of the :attr:`codeobject.co_freevars` attribute,
+ the term is also sometimes used as a synonym for :term:`closure variable`.
+
function
A series of statements which returns some value to a caller. It can also
be passed zero or more :term:`arguments ` which may be used in
@@ -497,7 +554,7 @@ Glossary
An object created by a :term:`generator` function.
Each :keyword:`yield` temporarily suspends processing, remembering the
- location execution state (including local variables and pending
+ execution state (including local variables and pending
try-statements). When the *generator iterator* resumes, it picks up where
it left off (in contrast to functions which start fresh on every
invocation).
@@ -550,7 +607,7 @@ Glossary
As of Python 3.13, the GIL can be disabled using the :option:`--disable-gil`
build configuration. After building Python with this option, code must be
- run with :option:`-X gil 0 <-X>` or after setting the :envvar:`PYTHON_GIL=0 `
+ run with :option:`-X gil=0 <-X>` or after setting the :envvar:`PYTHON_GIL=0 `
environment variable. This feature enables improved performance for
multi-threaded applications and makes it easier to use multi-core CPUs
efficiently. For more details, see :pep:`703`.
@@ -584,14 +641,12 @@ Glossary
which ships with the standard distribution of Python.
immortal
- If an object is immortal, its reference count is never modified, and
- therefore it is never deallocated.
-
- Built-in strings and singletons are immortal objects. For example,
- :const:`True` and :const:`None` singletons are immmortal.
+ *Immortal objects* are a CPython implementation detail introduced
+ in :pep:`683`.
- See `PEP 683 – Immortal Objects, Using a Fixed Refcount
- `_ for more information.
+ If an object is immortal, its :term:`reference count` is never modified,
+ and therefore it is never deallocated while the interpreter is running.
+ For example, :const:`True` and :const:`None` are immortal in CPython.
immutable
An object with a fixed value. Immutable objects include numbers, strings and
@@ -651,7 +706,7 @@ Glossary
iterables include all sequence types (such as :class:`list`, :class:`str`,
and :class:`tuple`) and some non-sequence types like :class:`dict`,
:term:`file objects `, and objects of any classes you define
- with an :meth:`~iterator.__iter__` method or with a
+ with an :meth:`~object.__iter__` method or with a
:meth:`~object.__getitem__` method
that implements :term:`sequence` semantics.
@@ -688,6 +743,9 @@ Glossary
CPython does not consistently apply the requirement that an iterator
define :meth:`~iterator.__iter__`.
+ And also please note that the free-threading CPython does not guarantee
+ the thread-safety of iterator operations.
+
key function
A key function or collation function is a callable that returns a value
@@ -729,6 +787,10 @@ Glossary
thread removes *key* from *mapping* after the test, but before the lookup.
This issue can be solved with locks or by using the EAFP approach.
+ lexical analyzer
+
+ Formal name for the *tokenizer*; see :term:`token`.
+
list
A built-in Python :term:`sequence`. Despite its name it is more akin
to an array in other languages than to a linked list since access to
@@ -743,10 +805,15 @@ Glossary
processed.
loader
- An object that loads a module. It must define a method named
- :meth:`load_module`. A loader is typically returned by a
- :term:`finder`. See :pep:`302` for details and
- :class:`importlib.abc.Loader` for an :term:`abstract base class`.
+ An object that loads a module.
+ It must define the :meth:`!exec_module` and :meth:`!create_module` methods
+ to implement the :class:`~importlib.abc.Loader` interface.
+ A loader is typically returned by a :term:`finder`.
+ See also:
+
+ * :ref:`finders-and-loaders`
+ * :class:`importlib.abc.Loader`
+ * :pep:`302`
locale encoding
On Unix, it is the encoding of the LC_CTYPE locale. It can be set with
@@ -816,6 +883,8 @@ Glossary
A namespace containing the import-related information used to load a
module. An instance of :class:`importlib.machinery.ModuleSpec`.
+ See also :ref:`module-specs`.
+
MRO
See :term:`method resolution order`.
@@ -861,11 +930,16 @@ Glossary
modules, respectively.
namespace package
- A :pep:`420` :term:`package` which serves only as a container for
- subpackages. Namespace packages may have no physical representation,
+ A :term:`package` which serves only as a container for subpackages.
+ Namespace packages may have no physical representation,
and specifically are not like a :term:`regular package` because they
have no ``__init__.py`` file.
+ Namespace packages allow several individually installable packages to have a common parent package.
+ Otherwise, it is recommended to use a :term:`regular package`.
+
+ For more information, see :pep:`420` and :ref:`reference-namespace-package`.
+
See also :term:`module`.
nested scope
@@ -889,6 +963,15 @@ Glossary
(methods). Also the ultimate base class of any :term:`new-style
class`.
+ optimized scope
+ A scope where target local variable names are reliably known to the
+ compiler when the code is compiled, allowing optimization of read and
+ write access to these names. The local namespaces for functions,
+ generators, coroutines, comprehensions, and generator expressions are
+ optimized in this fashion. Note: most interpreter optimizations are
+ applied to all scopes, only those relying on a known set of local
+ and nonlocal variable names are restricted to optimized scopes.
+
package
A Python :term:`module` which can contain submodules or recursively,
subpackages. Technically, a package is a Python module with a
@@ -1105,7 +1188,7 @@ Glossary
:class:`tuple`, and :class:`bytes`. Note that :class:`dict` also
supports :meth:`~object.__getitem__` and :meth:`!__len__`, but is considered a
mapping rather than a sequence because the lookups use arbitrary
- :term:`immutable` keys rather than integers.
+ :term:`hashable` keys rather than integers.
The :class:`collections.abc.Sequence` abstract base class
defines a much richer interface that goes beyond just
@@ -1134,16 +1217,12 @@ Glossary
(subscript) notation uses :class:`slice` objects internally.
soft deprecated
- A soft deprecation can be used when using an API which should no longer
- be used to write new code, but it remains safe to continue using it in
- existing code. The API remains documented and tested, but will not be
- developed further (no enhancement).
-
- The main difference between a "soft" and a (regular) "hard" deprecation
- is that the soft deprecation does not imply scheduling the removal of the
- deprecated API.
+ A soft deprecated API should not be used in new code,
+ but it is safe for already existing code to use it.
+ The API remains documented and tested, but will not be enhanced further.
- Another difference is that a soft deprecation does not issue a warning.
+ Soft deprecation, unlike normal deprecation, does not plan on removing the API
+ and will not emit warnings.
See `PEP 387: Soft Deprecation
`_.
@@ -1203,6 +1282,17 @@ Glossary
See also :term:`binary file` for a file object able to read and write
:term:`bytes-like objects `.
+ token
+
+ A small unit of source code, generated by the
+ :ref:`lexical analyzer ` (also called the *tokenizer*).
+ Names, numbers, strings, operators,
+ newlines and similar are represented by tokens.
+
+ The :mod:`tokenize` module exposes Python's lexical analyzer.
+ The :mod:`token` module contains information on the various types
+ of tokens.
+
triple-quoted string
A string which is bound by three instances of either a quotation mark
(") or an apostrophe ('). While they don't provide any functionality
@@ -1215,7 +1305,7 @@ Glossary
type
The type of a Python object determines what kind of object it is; every
object has a type. An object's type is accessible as its
- :attr:`~instance.__class__` attribute or can be retrieved with
+ :attr:`~object.__class__` attribute or can be retrieved with
``type(obj)``.
type alias
diff --git a/Doc/howto/annotations.rst b/Doc/howto/annotations.rst
index be8c7e6c827f57..174078b84aa5a8 100644
--- a/Doc/howto/annotations.rst
+++ b/Doc/howto/annotations.rst
@@ -102,9 +102,9 @@ Your code will have to have a separate code path if the object
you're examining is a class (``isinstance(o, type)``).
In that case, best practice relies on an implementation detail
of Python 3.9 and before: if a class has annotations defined,
-they are stored in the class's ``__dict__`` dictionary. Since
+they are stored in the class's :attr:`~type.__dict__` dictionary. Since
the class may or may not have annotations defined, best practice
-is to call the ``get`` method on the class dict.
+is to call the :meth:`~dict.get` method on the class dict.
To put it all together, here is some sample code that safely
accesses the ``__annotations__`` attribute on an arbitrary
@@ -121,8 +121,8 @@ the type of ``ann`` using :func:`isinstance` before further
examination.
Note that some exotic or malformed type objects may not have
-a ``__dict__`` attribute, so for extra safety you may also wish
-to use :func:`getattr` to access ``__dict__``.
+a :attr:`~type.__dict__` attribute, so for extra safety you may also wish
+to use :func:`getattr` to access :attr:`!__dict__`.
Manually Un-Stringizing Stringized Annotations
diff --git a/Doc/howto/argparse-optparse.rst b/Doc/howto/argparse-optparse.rst
new file mode 100644
index 00000000000000..b684619885b4c7
--- /dev/null
+++ b/Doc/howto/argparse-optparse.rst
@@ -0,0 +1,65 @@
+.. currentmodule:: argparse
+
+.. _upgrading-optparse-code:
+.. _migrating-optparse-code:
+
+============================================
+Migrating ``optparse`` code to ``argparse``
+============================================
+
+The :mod:`argparse` module offers several higher level features not natively
+provided by the :mod:`optparse` module, including:
+
+* Handling positional arguments.
+* Supporting subcommands.
+* Allowing alternative option prefixes like ``+`` and ``/``.
+* Handling zero-or-more and one-or-more style arguments.
+* Producing more informative usage messages.
+* Providing a much simpler interface for custom ``type`` and ``action``.
+
+Originally, the :mod:`argparse` module attempted to maintain compatibility
+with :mod:`optparse`. However, the fundamental design differences between
+supporting declarative command line option processing (while leaving positional
+argument processing to application code), and supporting both named options
+and positional arguments in the declarative interface mean that the
+API has diverged from that of ``optparse`` over time.
+
+As described in :ref:`choosing-an-argument-parser`, applications that are
+currently using :mod:`optparse` and are happy with the way it works can
+just continue to use ``optparse``.
+
+Application developers that are considering migrating should also review
+the list of intrinsic behavioural differences described in that section
+before deciding whether or not migration is desirable.
+
+For applications that do choose to migrate from :mod:`optparse` to :mod:`argparse`,
+the following suggestions should be helpful:
+
+* Replace all :meth:`optparse.OptionParser.add_option` calls with
+ :meth:`ArgumentParser.add_argument` calls.
+
+* Replace ``(options, args) = parser.parse_args()`` with ``args =
+ parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument`
+ calls for the positional arguments. Keep in mind that what was previously
+ called ``options``, now in the :mod:`argparse` context is called ``args``.
+
+* Replace :meth:`optparse.OptionParser.disable_interspersed_args`
+ by using :meth:`~ArgumentParser.parse_intermixed_args` instead of
+ :meth:`~ArgumentParser.parse_args`.
+
+* Replace callback actions and the ``callback_*`` keyword arguments with
+ ``type`` or ``action`` arguments.
+
+* Replace string names for ``type`` keyword arguments with the corresponding
+ type objects (e.g. int, float, complex, etc).
+
+* Replace :class:`optparse.Values` with :class:`Namespace` and
+ :exc:`optparse.OptionError` and :exc:`optparse.OptionValueError` with
+ :exc:`ArgumentError`.
+
+* Replace strings with implicit arguments such as ``%default`` or ``%prog`` with
+ the standard Python syntax to use dictionaries to format strings, that is,
+ ``%(default)s`` and ``%(prog)s``.
+
+* Replace the OptionParser constructor ``version`` argument with a call to
+ ``parser.add_argument('--version', action='version', version='')``.
diff --git a/Doc/howto/argparse.rst b/Doc/howto/argparse.rst
index ae5bab90bf8131..902c50de00803c 100644
--- a/Doc/howto/argparse.rst
+++ b/Doc/howto/argparse.rst
@@ -13,11 +13,16 @@ recommended command-line parsing module in the Python standard library.
.. note::
- There are two other modules that fulfill the same task, namely
- :mod:`getopt` (an equivalent for ``getopt()`` from the C
- language) and the deprecated :mod:`optparse`.
- Note also that :mod:`argparse` is based on :mod:`optparse`,
- and therefore very similar in terms of usage.
+ The standard library includes two other libraries directly related
+ to command-line parameter processing: the lower level :mod:`optparse`
+ module (which may require more code to configure for a given application,
+ but also allows an application to request behaviors that ``argparse``
+ doesn't support), and the very low level :mod:`getopt` (which specifically
+ serves as an equivalent to the :c:func:`!getopt` family of functions
+ available to C programmers).
+ While neither of those modules is covered directly in this guide, many of
+ the core concepts in ``argparse`` first originated in ``optparse``, so
+ some aspects of this tutorial will also be relevant to ``optparse`` users.
Concepts
@@ -444,7 +449,7 @@ And the output:
options:
-h, --help show this help message and exit
- -v {0,1,2}, --verbosity {0,1,2}
+ -v, --verbosity {0,1,2}
increase output verbosity
Note that the change also reflects both in the error message as well as the
@@ -841,6 +846,53 @@ translated messages.
To translate your own strings in the :mod:`argparse` output, use :mod:`gettext`.
+Custom type converters
+======================
+
+The :mod:`argparse` module allows you to specify custom type converters for
+your command-line arguments. This allows you to modify user input before it's
+stored in the :class:`argparse.Namespace`. This can be useful when you need to
+pre-process the input before it is used in your program.
+
+When using a custom type converter, you can use any callable that takes a
+single string argument (the argument value) and returns the converted value.
+However, if you need to handle more complex scenarios, you can use a custom
+action class with the **action** parameter instead.
+
+For example, let's say you want to handle arguments with different prefixes and
+process them accordingly::
+
+ import argparse
+
+ parser = argparse.ArgumentParser(prefix_chars='-+')
+
+ parser.add_argument('-a', metavar='', action='append',
+ type=lambda x: ('-', x))
+ parser.add_argument('+a', metavar='', action='append',
+ type=lambda x: ('+', x))
+
+ args = parser.parse_args()
+ print(args)
+
+Output:
+
+.. code-block:: shell-session
+
+ $ python prog.py -a value1 +a value2
+ Namespace(a=[('-', 'value1'), ('+', 'value2')])
+
+In this example, we:
+
+* Created a parser with custom prefix characters using the ``prefix_chars``
+ parameter.
+
+* Defined two arguments, ``-a`` and ``+a``, which used the ``type`` parameter to
+ create custom type converters to store the value in a tuple with the prefix.
+
+Without the custom type converters, the arguments would have treated the ``-a``
+and ``+a`` as the same argument, which would have been undesirable. By using custom
+type converters, we were able to differentiate between the two arguments.
+
Conclusion
==========
diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst
index f9ad81e38f8dc3..6994a5328e8149 100644
--- a/Doc/howto/curses.rst
+++ b/Doc/howto/curses.rst
@@ -145,8 +145,8 @@ importing the :func:`curses.wrapper` function and using it like this::
v = i-10
stdscr.addstr(i, 0, '10 divided by {} is {}'.format(v, 10/v))
- stdscr.refresh()
- stdscr.getkey()
+ stdscr.refresh()
+ stdscr.getkey()
wrapper(main)
diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst
index 51f9f4a6556e57..50a368b7712938 100644
--- a/Doc/howto/descriptor.rst
+++ b/Doc/howto/descriptor.rst
@@ -42,7 +42,7 @@ add new capabilities one by one.
Simple example: A descriptor that returns a constant
----------------------------------------------------
-The :class:`Ten` class is a descriptor whose :meth:`__get__` method always
+The :class:`!Ten` class is a descriptor whose :meth:`~object.__get__` method always
returns the constant ``10``:
.. testcode::
@@ -120,10 +120,10 @@ different, updated answers each time::
2
Besides showing how descriptors can run computations, this example also
-reveals the purpose of the parameters to :meth:`__get__`. The *self*
+reveals the purpose of the parameters to :meth:`~object.__get__`. The *self*
parameter is *size*, an instance of *DirectorySize*. The *obj* parameter is
either *g* or *s*, an instance of *Directory*. It is the *obj* parameter that
-lets the :meth:`__get__` method learn the target directory. The *objtype*
+lets the :meth:`~object.__get__` method learn the target directory. The *objtype*
parameter is the class *Directory*.
@@ -133,7 +133,7 @@ Managed attributes
A popular use for descriptors is managing access to instance data. The
descriptor is assigned to a public attribute in the class dictionary while the
actual data is stored as a private attribute in the instance dictionary. The
-descriptor's :meth:`__get__` and :meth:`__set__` methods are triggered when
+descriptor's :meth:`~object.__get__` and :meth:`~object.__set__` methods are triggered when
the public attribute is accessed.
In the following example, *age* is the public attribute and *_age* is the
@@ -215,9 +215,9 @@ Customized names
When a class uses descriptors, it can inform each descriptor about which
variable name was used.
-In this example, the :class:`Person` class has two descriptor instances,
-*name* and *age*. When the :class:`Person` class is defined, it makes a
-callback to :meth:`__set_name__` in *LoggedAccess* so that the field names can
+In this example, the :class:`!Person` class has two descriptor instances,
+*name* and *age*. When the :class:`!Person` class is defined, it makes a
+callback to :meth:`~object.__set_name__` in *LoggedAccess* so that the field names can
be recorded, giving each descriptor its own *public_name* and *private_name*:
.. testcode::
@@ -253,8 +253,8 @@ be recorded, giving each descriptor its own *public_name* and *private_name*:
def birthday(self):
self.age += 1
-An interactive session shows that the :class:`Person` class has called
-:meth:`__set_name__` so that the field names would be recorded. Here
+An interactive session shows that the :class:`!Person` class has called
+:meth:`~object.__set_name__` so that the field names would be recorded. Here
we call :func:`vars` to look up the descriptor without triggering it:
.. doctest::
@@ -294,10 +294,10 @@ The two *Person* instances contain only the private names:
Closing thoughts
----------------
-A :term:`descriptor` is what we call any object that defines :meth:`__get__`,
-:meth:`__set__`, or :meth:`__delete__`.
+A :term:`descriptor` is what we call any object that defines :meth:`~object.__get__`,
+:meth:`~object.__set__`, or :meth:`~object.__delete__`.
-Optionally, descriptors can have a :meth:`__set_name__` method. This is only
+Optionally, descriptors can have a :meth:`~object.__set_name__` method. This is only
used in cases where a descriptor needs to know either the class where it was
created or the name of class variable it was assigned to. (This method, if
present, is called even if the class is not a descriptor.)
@@ -337,7 +337,7 @@ any data, it verifies that the new value meets various type and range
restrictions. If those restrictions aren't met, it raises an exception to
prevent data corruption at its source.
-This :class:`Validator` class is both an :term:`abstract base class` and a
+This :class:`!Validator` class is both an :term:`abstract base class` and a
managed attribute descriptor:
.. testcode::
@@ -360,8 +360,8 @@ managed attribute descriptor:
def validate(self, value):
pass
-Custom validators need to inherit from :class:`Validator` and must supply a
-:meth:`validate` method to test various restrictions as needed.
+Custom validators need to inherit from :class:`!Validator` and must supply a
+:meth:`!validate` method to test various restrictions as needed.
Custom validators
@@ -369,13 +369,13 @@ Custom validators
Here are three practical data validation utilities:
-1) :class:`OneOf` verifies that a value is one of a restricted set of options.
+1) :class:`!OneOf` verifies that a value is one of a restricted set of options.
-2) :class:`Number` verifies that a value is either an :class:`int` or
+2) :class:`!Number` verifies that a value is either an :class:`int` or
:class:`float`. Optionally, it verifies that a value is between a given
minimum or maximum.
-3) :class:`String` verifies that a value is a :class:`str`. Optionally, it
+3) :class:`!String` verifies that a value is a :class:`str`. Optionally, it
validates a given minimum or maximum length. It can validate a
user-defined `predicate
`_ as well.
@@ -389,7 +389,9 @@ Here are three practical data validation utilities:
def validate(self, value):
if value not in self.options:
- raise ValueError(f'Expected {value!r} to be one of {self.options!r}')
+ raise ValueError(
+ f'Expected {value!r} to be one of {self.options!r}'
+ )
class Number(Validator):
@@ -469,6 +471,7 @@ The descriptors prevent invalid instances from being created:
Traceback (most recent call last):
...
ValueError: Expected -5 to be at least 0
+
>>> Component('WIDGET', 'metal', 'V') # Blocked: 'V' isn't a number
Traceback (most recent call last):
...
@@ -498,8 +501,8 @@ Definition and introduction
---------------------------
In general, a descriptor is an attribute value that has one of the methods in
-the descriptor protocol. Those methods are :meth:`__get__`, :meth:`__set__`,
-and :meth:`__delete__`. If any of those methods are defined for an
+the descriptor protocol. Those methods are :meth:`~object.__get__`, :meth:`~object.__set__`,
+and :meth:`~object.__delete__`. If any of those methods are defined for an
attribute, it is said to be a :term:`descriptor`.
The default behavior for attribute access is to get, set, or delete the
@@ -513,7 +516,7 @@ were defined.
Descriptors are a powerful, general purpose protocol. They are the mechanism
behind properties, methods, static methods, class methods, and
-:func:`super()`. They are used throughout Python itself. Descriptors
+:func:`super`. They are used throughout Python itself. Descriptors
simplify the underlying C code and offer a flexible set of new tools for
everyday Python programs.
@@ -531,8 +534,8 @@ That is all there is to it. Define any of these methods and an object is
considered a descriptor and can override default behavior upon being looked up
as an attribute.
-If an object defines :meth:`__set__` or :meth:`__delete__`, it is considered
-a data descriptor. Descriptors that only define :meth:`__get__` are called
+If an object defines :meth:`~object.__set__` or :meth:`~object.__delete__`, it is considered
+a data descriptor. Descriptors that only define :meth:`~object.__get__` are called
non-data descriptors (they are often used for methods but other uses are
possible).
@@ -542,9 +545,9 @@ has an entry with the same name as a data descriptor, the data descriptor
takes precedence. If an instance's dictionary has an entry with the same
name as a non-data descriptor, the dictionary entry takes precedence.
-To make a read-only data descriptor, define both :meth:`__get__` and
-:meth:`__set__` with the :meth:`__set__` raising an :exc:`AttributeError` when
-called. Defining the :meth:`__set__` method with an exception raising
+To make a read-only data descriptor, define both :meth:`~object.__get__` and
+:meth:`~object.__set__` with the :meth:`~object.__set__` raising an :exc:`AttributeError` when
+called. Defining the :meth:`~object.__set__` method with an exception raising
placeholder is enough to make it a data descriptor.
@@ -559,8 +562,8 @@ attribute access.
The expression ``obj.x`` looks up the attribute ``x`` in the chain of
namespaces for ``obj``. If the search finds a descriptor outside of the
-instance ``__dict__``, its :meth:`__get__` method is invoked according to the
-precedence rules listed below.
+instance :attr:`~object.__dict__`, its :meth:`~object.__get__` method is
+invoked according to the precedence rules listed below.
The details of invocation depend on whether ``obj`` is an object, class, or
instance of super.
@@ -571,7 +574,7 @@ Invocation from an instance
Instance lookup scans through a chain of namespaces giving data descriptors
the highest priority, followed by instance variables, then non-data
-descriptors, then class variables, and lastly :meth:`__getattr__` if it is
+descriptors, then class variables, and lastly :meth:`~object.__getattr__` if it is
provided.
If a descriptor is found for ``a.x``, then it is invoked with:
@@ -716,12 +719,12 @@ a pure Python equivalent:
>>> object_getattribute(u2, 'x') == u2.x == (D1, u2, U2)
True
-Note, there is no :meth:`__getattr__` hook in the :meth:`__getattribute__`
-code. That is why calling :meth:`__getattribute__` directly or with
-``super().__getattribute__`` will bypass :meth:`__getattr__` entirely.
+Note, there is no :meth:`~object.__getattr__` hook in the :meth:`~object.__getattribute__`
+code. That is why calling :meth:`~object.__getattribute__` directly or with
+``super().__getattribute__`` will bypass :meth:`~object.__getattr__` entirely.
Instead, it is the dot operator and the :func:`getattr` function that are
-responsible for invoking :meth:`__getattr__` whenever :meth:`__getattribute__`
+responsible for invoking :meth:`~object.__getattr__` whenever :meth:`~object.__getattribute__`
raises an :exc:`AttributeError`. Their logic is encapsulated in a helper
function:
@@ -773,8 +776,8 @@ Invocation from a class
-----------------------
The logic for a dotted lookup such as ``A.x`` is in
-:meth:`type.__getattribute__`. The steps are similar to those for
-:meth:`object.__getattribute__` but the instance dictionary lookup is replaced
+:meth:`!type.__getattribute__`. The steps are similar to those for
+:meth:`!object.__getattribute__` but the instance dictionary lookup is replaced
by a search through the class's :term:`method resolution order`.
If a descriptor is found, it is invoked with ``desc.__get__(None, A)``.
@@ -786,8 +789,8 @@ The full C implementation can be found in :c:func:`!type_getattro` and
Invocation from super
---------------------
-The logic for super's dotted lookup is in the :meth:`__getattribute__` method for
-object returned by :class:`super()`.
+The logic for super's dotted lookup is in the :meth:`~object.__getattribute__` method for
+object returned by :func:`super`.
A dotted lookup such as ``super(A, obj).m`` searches ``obj.__class__.__mro__``
for the base class ``B`` immediately following ``A`` and then returns
@@ -803,21 +806,21 @@ The full C implementation can be found in :c:func:`!super_getattro` in
Summary of invocation logic
---------------------------
-The mechanism for descriptors is embedded in the :meth:`__getattribute__()`
+The mechanism for descriptors is embedded in the :meth:`~object.__getattribute__`
methods for :class:`object`, :class:`type`, and :func:`super`.
The important points to remember are:
-* Descriptors are invoked by the :meth:`__getattribute__` method.
+* Descriptors are invoked by the :meth:`~object.__getattribute__` method.
* Classes inherit this machinery from :class:`object`, :class:`type`, or
:func:`super`.
-* Overriding :meth:`__getattribute__` prevents automatic descriptor calls
+* Overriding :meth:`~object.__getattribute__` prevents automatic descriptor calls
because all the descriptor logic is in that method.
-* :meth:`object.__getattribute__` and :meth:`type.__getattribute__` make
- different calls to :meth:`__get__`. The first includes the instance and may
+* :meth:`!object.__getattribute__` and :meth:`!type.__getattribute__` make
+ different calls to :meth:`~object.__get__`. The first includes the instance and may
include the class. The second puts in ``None`` for the instance and always
includes the class.
@@ -832,16 +835,16 @@ Automatic name notification
Sometimes it is desirable for a descriptor to know what class variable name it
was assigned to. When a new class is created, the :class:`type` metaclass
scans the dictionary of the new class. If any of the entries are descriptors
-and if they define :meth:`__set_name__`, that method is called with two
+and if they define :meth:`~object.__set_name__`, that method is called with two
arguments. The *owner* is the class where the descriptor is used, and the
*name* is the class variable the descriptor was assigned to.
The implementation details are in :c:func:`!type_new` and
:c:func:`!set_names` in :source:`Objects/typeobject.c`.
-Since the update logic is in :meth:`type.__new__`, notifications only take
+Since the update logic is in :meth:`!type.__new__`, notifications only take
place at the time of class creation. If descriptors are added to the class
-afterwards, :meth:`__set_name__` will need to be called manually.
+afterwards, :meth:`~object.__set_name__` will need to be called manually.
ORM example
@@ -870,7 +873,7 @@ care of lookups or updates:
conn.execute(self.store, [value, obj.key])
conn.commit()
-We can use the :class:`Field` class to define `models
+We can use the :class:`!Field` class to define `models
`_ that describe the schema for
each table in a database:
@@ -990,7 +993,7 @@ The documentation shows a typical use to define a managed attribute ``x``:
AttributeError: 'C' object has no attribute '_C__x'
To see how :func:`property` is implemented in terms of the descriptor protocol,
-here is a pure Python equivalent:
+here is a pure Python equivalent that implements most of the core functionality:
.. testcode::
@@ -1004,59 +1007,35 @@ here is a pure Python equivalent:
if doc is None and fget is not None:
doc = fget.__doc__
self.__doc__ = doc
- self._name = None
def __set_name__(self, owner, name):
- self._name = name
-
- @property
- def __name__(self):
- return self._name if self._name is not None else self.fget.__name__
-
- @__name__.setter
- def __name__(self, value):
- self._name = value
+ self.__name__ = name
def __get__(self, obj, objtype=None):
if obj is None:
return self
if self.fget is None:
- raise AttributeError(
- f'property {self.__name__!r} of {type(obj).__name__!r} '
- 'object has no getter'
- )
+ raise AttributeError
return self.fget(obj)
def __set__(self, obj, value):
if self.fset is None:
- raise AttributeError(
- f'property {self.__name__!r} of {type(obj).__name__!r} '
- 'object has no setter'
- )
+ raise AttributeError
self.fset(obj, value)
def __delete__(self, obj):
if self.fdel is None:
- raise AttributeError(
- f'property {self.__name__!r} of {type(obj).__name__!r} '
- 'object has no deleter'
- )
+ raise AttributeError
self.fdel(obj)
def getter(self, fget):
- prop = type(self)(fget, self.fset, self.fdel, self.__doc__)
- prop._name = self._name
- return prop
+ return type(self)(fget, self.fset, self.fdel, self.__doc__)
def setter(self, fset):
- prop = type(self)(self.fget, fset, self.fdel, self.__doc__)
- prop._name = self._name
- return prop
+ return type(self)(self.fget, fset, self.fdel, self.__doc__)
def deleter(self, fdel):
- prop = type(self)(self.fget, self.fset, fdel, self.__doc__)
- prop._name = self._name
- return prop
+ return type(self)(self.fget, self.fset, fdel, self.__doc__)
.. testcode::
:hide:
@@ -1119,23 +1098,23 @@ here is a pure Python equivalent:
>>> try:
... cc.no_getter
... except AttributeError as e:
- ... e.args[0]
+ ... type(e).__name__
...
- "property 'no_getter' of 'CC' object has no getter"
+ 'AttributeError'
>>> try:
... cc.no_setter = 33
... except AttributeError as e:
- ... e.args[0]
+ ... type(e).__name__
...
- "property 'no_setter' of 'CC' object has no setter"
+ 'AttributeError'
>>> try:
... del cc.no_deleter
... except AttributeError as e:
- ... e.args[0]
+ ... type(e).__name__
...
- "property 'no_deleter' of 'CC' object has no deleter"
+ 'AttributeError'
>>> CC.no_doc.__doc__ is None
True
@@ -1161,7 +1140,7 @@ to wrap access to the value attribute in a property data descriptor:
self.recalc()
return self._value
-Either the built-in :func:`property` or our :func:`Property` equivalent would
+Either the built-in :func:`property` or our :func:`!Property` equivalent would
work in this example.
@@ -1208,7 +1187,7 @@ roughly equivalent to:
return self
To support automatic creation of methods, functions include the
-:meth:`__get__` method for binding methods during attribute access. This
+:meth:`~object.__get__` method for binding methods during attribute access. This
means that functions are non-data descriptors that return bound methods
during dotted lookup from an instance. Here's how it works:
@@ -1252,19 +1231,19 @@ The function has a :term:`qualified name` attribute to support introspection:
'D.f'
Accessing the function through the class dictionary does not invoke
-:meth:`__get__`. Instead, it just returns the underlying function object::
+:meth:`~object.__get__`. Instead, it just returns the underlying function object::
>>> D.__dict__['f']
-Dotted access from a class calls :meth:`__get__` which just returns the
+Dotted access from a class calls :meth:`~object.__get__` which just returns the
underlying function unchanged::
>>> D.f
The interesting behavior occurs during dotted access from an instance. The
-dotted lookup calls :meth:`__get__` which returns a bound method object::
+dotted lookup calls :meth:`~object.__get__` which returns a bound method object::
>>> d = D()
>>> d.f
@@ -1289,7 +1268,7 @@ Kinds of methods
Non-data descriptors provide a simple mechanism for variations on the usual
patterns of binding functions into methods.
-To recap, functions have a :meth:`__get__` method so that they can be converted
+To recap, functions have a :meth:`~object.__get__` method so that they can be converted
to a method when accessed as attributes. The non-data descriptor transforms an
``obj.f(*args)`` call into ``f(obj, *args)``. Calling ``cls.f(*args)``
becomes ``f(*args)``.
@@ -1326,8 +1305,8 @@ mean, median, and other descriptive statistics that depend on the data. However,
there may be useful functions which are conceptually related but do not depend
on the data. For instance, ``erf(x)`` is handy conversion routine that comes up
in statistical work but does not directly depend on a particular dataset.
-It can be called either from an object or the class: ``s.erf(1.5) --> .9332`` or
-``Sample.erf(1.5) --> .9332``.
+It can be called either from an object or the class: ``s.erf(1.5) --> 0.9332``
+or ``Sample.erf(1.5) --> 0.9332``.
Since static methods return the underlying function with no changes, the
example calls are unexciting:
@@ -1688,7 +1667,7 @@ by member descriptors:
'Emulate member_repr() in Objects/descrobject.c'
return f''
-The :meth:`type.__new__` method takes care of adding member objects to class
+The :meth:`!type.__new__` method takes care of adding member objects to class
variables:
.. testcode::
@@ -1739,7 +1718,7 @@ Python:
)
super().__delattr__(name)
-To use the simulation in a real class, just inherit from :class:`Object` and
+To use the simulation in a real class, just inherit from :class:`!Object` and
set the :term:`metaclass` to :class:`Type`:
.. testcode::
diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst
index 30be15230fc088..6441b7aed1eda8 100644
--- a/Doc/howto/enum.rst
+++ b/Doc/howto/enum.rst
@@ -1,3 +1,5 @@
+.. _enum-howto:
+
==========
Enum HOWTO
==========
@@ -7,7 +9,7 @@ Enum HOWTO
.. currentmodule:: enum
An :class:`Enum` is a set of symbolic names bound to unique values. They are
-similar to global variables, but they offer a more useful :func:`repr()`,
+similar to global variables, but they offer a more useful :func:`repr`,
grouping, type-safety, and a few other features.
They are most useful when you have a variable that can take one of a limited
@@ -62,12 +64,12 @@ The *type* of an enumeration member is the enum it belongs to::
>>> isinstance(Weekday.FRIDAY, Weekday)
True
-Enum members have an attribute that contains just their :attr:`name`::
+Enum members have an attribute that contains just their :attr:`!name`::
>>> print(Weekday.TUESDAY.name)
TUESDAY
-Likewise, they have an attribute for their :attr:`value`::
+Likewise, they have an attribute for their :attr:`!value`::
>>> Weekday.WEDNESDAY.value
@@ -75,17 +77,18 @@ Likewise, they have an attribute for their :attr:`value`::
Unlike many languages that treat enumerations solely as name/value pairs,
Python Enums can have behavior added. For example, :class:`datetime.date`
-has two methods for returning the weekday: :meth:`weekday` and :meth:`isoweekday`.
+has two methods for returning the weekday:
+:meth:`~datetime.date.weekday` and :meth:`~datetime.date.isoweekday`.
The difference is that one of them counts from 0-6 and the other from 1-7.
-Rather than keep track of that ourselves we can add a method to the :class:`Weekday`
-enum to extract the day from the :class:`date` instance and return the matching
+Rather than keep track of that ourselves we can add a method to the :class:`!Weekday`
+enum to extract the day from the :class:`~datetime.date` instance and return the matching
enum member::
@classmethod
def from_date(cls, date):
return cls(date.isoweekday())
-The complete :class:`Weekday` enum now looks like this::
+The complete :class:`!Weekday` enum now looks like this::
>>> class Weekday(Enum):
... MONDAY = 1
@@ -108,7 +111,7 @@ Now we can find out what today is! Observe::
Of course, if you're reading this on some other day, you'll see that day instead.
-This :class:`Weekday` enum is great if our variable only needs one day, but
+This :class:`!Weekday` enum is great if our variable only needs one day, but
what if we need several? Maybe we're writing a function to plot chores during
a week, and don't want to use a :class:`list` -- we could use a different type
of :class:`Enum`::
@@ -126,7 +129,7 @@ of :class:`Enum`::
We've changed two things: we're inherited from :class:`Flag`, and the values are
all powers of 2.
-Just like the original :class:`Weekday` enum above, we can have a single selection::
+Just like the original :class:`!Weekday` enum above, we can have a single selection::
>>> first_week_day = Weekday.MONDAY
>>> first_week_day
@@ -165,7 +168,7 @@ And a function to display the chores for a given day::
answer SO questions
In cases where the actual values of the members do not matter, you can save
-yourself some work and use :func:`auto()` for the values::
+yourself some work and use :func:`auto` for the values::
>>> from enum import auto
>>> class Weekday(Flag):
@@ -201,7 +204,7 @@ If you want to access enum members by *name*, use item access::
>>> Color['GREEN']
-If you have an enum member and need its :attr:`name` or :attr:`value`::
+If you have an enum member and need its :attr:`!name` or :attr:`!value`::
>>> member = Color.RED
>>> member.name
@@ -282,7 +285,7 @@ If the exact value is unimportant you can use :class:`auto`::
>>> [member.value for member in Color]
[1, 2, 3]
-The values are chosen by :func:`_generate_next_value_`, which can be
+The values are chosen by :func:`~Enum._generate_next_value_`, which can be
overridden::
>>> class AutoName(Enum):
@@ -301,7 +304,7 @@ overridden::
.. note::
- The :meth:`_generate_next_value_` method must be defined before any members.
+ The :meth:`~Enum._generate_next_value_` method must be defined before any members.
Iteration
---------
@@ -422,18 +425,18 @@ Then::
The rules for what is allowed are as follows: names that start and end with
a single underscore are reserved by enum and cannot be used; all other
attributes defined within an enumeration will become members of this
-enumeration, with the exception of special methods (:meth:`__str__`,
-:meth:`__add__`, etc.), descriptors (methods are also descriptors), and
-variable names listed in :attr:`_ignore_`.
+enumeration, with the exception of special methods (:meth:`~object.__str__`,
+:meth:`~object.__add__`, etc.), descriptors (methods are also descriptors), and
+variable names listed in :attr:`~Enum._ignore_`.
-Note: if your enumeration defines :meth:`__new__` and/or :meth:`__init__`,
+Note: if your enumeration defines :meth:`~object.__new__` and/or :meth:`~object.__init__`,
any value(s) given to the enum member will be passed into those methods.
See `Planet`_ for an example.
.. note::
- The :meth:`__new__` method, if defined, is used during creation of the Enum
- members; it is then replaced by Enum's :meth:`__new__` which is used after
+ The :meth:`~object.__new__` method, if defined, is used during creation of the Enum
+ members; it is then replaced by Enum's :meth:`~object.__new__` which is used after
class creation for lookup of existing members. See :ref:`new-vs-init` for
more details.
@@ -542,7 +545,7 @@ from that module.
nested in other classes.
It is possible to modify how enum members are pickled/unpickled by defining
-:meth:`__reduce_ex__` in the enumeration class. The default method is by-value,
+:meth:`~object.__reduce_ex__` in the enumeration class. The default method is by-value,
but enums with complicated values may want to use by-name::
>>> import enum
@@ -578,7 +581,7 @@ values. The last two options enable assigning arbitrary values to
enumerations; the others auto-assign increasing integers starting with 1 (use
the ``start`` parameter to specify a different starting value). A
new class derived from :class:`Enum` is returned. In other words, the above
-assignment to :class:`Animal` is equivalent to::
+assignment to :class:`!Animal` is equivalent to::
>>> class Animal(Enum):
... ANT = 1
@@ -606,7 +609,7 @@ The solution is to specify the module name explicitly as follows::
the source, pickling will be disabled.
The new pickle protocol 4 also, in some circumstances, relies on
-:attr:`~definition.__qualname__` being set to the location where pickle will be able
+:attr:`~type.__qualname__` being set to the location where pickle will be able
to find the class. For example, if the class was made available in class
SomeData in the global scope::
@@ -889,7 +892,7 @@ simple to implement independently::
pass
This demonstrates how similar derived enumerations can be defined; for example
-a :class:`FloatEnum` that mixes in :class:`float` instead of :class:`int`.
+a :class:`!FloatEnum` that mixes in :class:`float` instead of :class:`int`.
Some rules:
@@ -903,32 +906,32 @@ Some rules:
additional type, all the members must have values of that type, e.g.
:class:`int` above. This restriction does not apply to mix-ins which only
add methods and don't specify another type.
-4. When another data type is mixed in, the :attr:`value` attribute is *not the
+4. When another data type is mixed in, the :attr:`~Enum.value` attribute is *not the
same* as the enum member itself, although it is equivalent and will compare
equal.
-5. A ``data type`` is a mixin that defines :meth:`__new__`, or a
+5. A ``data type`` is a mixin that defines :meth:`~object.__new__`, or a
:class:`~dataclasses.dataclass`
6. %-style formatting: ``%s`` and ``%r`` call the :class:`Enum` class's
- :meth:`__str__` and :meth:`__repr__` respectively; other codes (such as
+ :meth:`~object.__str__` and :meth:`~object.__repr__` respectively; other codes (such as
``%i`` or ``%h`` for IntEnum) treat the enum member as its mixed-in type.
7. :ref:`Formatted string literals `, :meth:`str.format`,
- and :func:`format` will use the enum's :meth:`__str__` method.
+ and :func:`format` will use the enum's :meth:`~object.__str__` method.
.. note::
Because :class:`IntEnum`, :class:`IntFlag`, and :class:`StrEnum` are
designed to be drop-in replacements for existing constants, their
- :meth:`__str__` method has been reset to their data types'
- :meth:`__str__` method.
+ :meth:`~object.__str__` method has been reset to their data types'
+ :meth:`~object.__str__` method.
.. _new-vs-init:
-When to use :meth:`__new__` vs. :meth:`__init__`
-------------------------------------------------
+When to use :meth:`~object.__new__` vs. :meth:`~object.__init__`
+----------------------------------------------------------------
-:meth:`__new__` must be used whenever you want to customize the actual value of
+:meth:`~object.__new__` must be used whenever you want to customize the actual value of
the :class:`Enum` member. Any other modifications may go in either
-:meth:`__new__` or :meth:`__init__`, with :meth:`__init__` being preferred.
+:meth:`~object.__new__` or :meth:`~object.__init__`, with :meth:`~object.__init__` being preferred.
For example, if you want to pass several items to the constructor, but only
want one of them to be the value::
@@ -967,11 +970,11 @@ Finer Points
Supported ``__dunder__`` names
""""""""""""""""""""""""""""""
-:attr:`__members__` is a read-only ordered mapping of ``member_name``:``member``
+:attr:`~enum.EnumType.__members__` is a read-only ordered mapping of ``member_name``:``member``
items. It is only available on the class.
-:meth:`__new__`, if specified, must create and return the enum members; it is
-also a very good idea to set the member's :attr:`_value_` appropriately. Once
+:meth:`~object.__new__`, if specified, must create and return the enum members; it is
+also a very good idea to set the member's :attr:`~Enum._value_` appropriately. Once
all the members are created it is no longer used.
@@ -987,9 +990,9 @@ Supported ``_sunder_`` names
from the final class
- :meth:`~Enum._generate_next_value_` -- used to get an appropriate value for
an enum member; may be overridden
-- :meth:`~Enum._add_alias_` -- adds a new name as an alias to an existing
+- :meth:`~EnumType._add_alias_` -- adds a new name as an alias to an existing
member.
-- :meth:`~Enum._add_value_alias_` -- adds a new value as an alias to an
+- :meth:`~EnumType._add_value_alias_` -- adds a new value as an alias to an
existing member. See `MultiValueEnum`_ for an example.
.. note::
@@ -1007,7 +1010,7 @@ Supported ``_sunder_`` names
.. versionadded:: 3.7 ``_ignore_``
.. versionadded:: 3.13 ``_add_alias_``, ``_add_value_alias_``
-To help keep Python 2 / Python 3 code in sync an :attr:`_order_` attribute can
+To help keep Python 2 / Python 3 code in sync an :attr:`~Enum._order_` attribute can
be provided. It will be checked against the actual order of the enumeration
and raise an error if the two do not match::
@@ -1025,7 +1028,7 @@ and raise an error if the two do not match::
.. note::
- In Python 2 code the :attr:`_order_` attribute is necessary as definition
+ In Python 2 code the :attr:`~Enum._order_` attribute is necessary as definition
order is lost before it can be recorded.
@@ -1150,6 +1153,14 @@ the following are true:
>>> (Color.RED | Color.GREEN).name
'RED|GREEN'
+ >>> class Perm(IntFlag):
+ ... R = 4
+ ... W = 2
+ ... X = 1
+ ...
+ >>> (Perm.R & Perm.W).name is None # effectively Perm(0)
+ True
+
- multi-bit flags, aka aliases, can be returned from operations::
>>> Color.RED | Color.BLUE
@@ -1206,12 +1217,12 @@ Enum Classes
^^^^^^^^^^^^
The :class:`EnumType` metaclass is responsible for providing the
-:meth:`__contains__`, :meth:`__dir__`, :meth:`__iter__` and other methods that
+:meth:`~object.__contains__`, :meth:`~object.__dir__`, :meth:`~object.__iter__` and other methods that
allow one to do things with an :class:`Enum` class that fail on a typical
class, such as ``list(Color)`` or ``some_enum_var in Color``. :class:`EnumType` is
responsible for ensuring that various other methods on the final :class:`Enum`
-class are correct (such as :meth:`__new__`, :meth:`__getnewargs__`,
-:meth:`__str__` and :meth:`__repr__`).
+class are correct (such as :meth:`~object.__new__`, :meth:`~object.__getnewargs__`,
+:meth:`~object.__str__` and :meth:`~object.__repr__`).
Flag Classes
^^^^^^^^^^^^
@@ -1226,7 +1237,7 @@ Enum Members (aka instances)
The most interesting thing about enum members is that they are singletons.
:class:`EnumType` creates them all while it is creating the enum class itself,
-and then puts a custom :meth:`__new__` in place to ensure that no new ones are
+and then puts a custom :meth:`~object.__new__` in place to ensure that no new ones are
ever instantiated by returning only the existing member instances.
Flag Members
@@ -1274,7 +1285,7 @@ is. There are several ways to define this type of simple enumeration:
- use instances of :class:`auto` for the value
- use instances of :class:`object` as the value
- use a descriptive string as the value
-- use a tuple as the value and a custom :meth:`__new__` to replace the
+- use a tuple as the value and a custom :meth:`~object.__new__` to replace the
tuple with an :class:`int` value
Using any of these methods signifies to the user that these values are not
@@ -1310,7 +1321,7 @@ Using :class:`object` would look like::
>
This is also a good example of why you might want to write your own
-:meth:`__repr__`::
+:meth:`~object.__repr__`::
>>> class Color(Enum):
... RED = object()
@@ -1338,10 +1349,10 @@ Using a string as the value would look like::
-Using a custom :meth:`__new__`
-""""""""""""""""""""""""""""""
+Using a custom :meth:`~object.__new__`
+""""""""""""""""""""""""""""""""""""""
-Using an auto-numbering :meth:`__new__` would look like::
+Using an auto-numbering :meth:`~object.__new__` would look like::
>>> class AutoNumber(Enum):
... def __new__(cls):
@@ -1387,8 +1398,8 @@ to handle any extra arguments::
.. note::
- The :meth:`__new__` method, if defined, is used during creation of the Enum
- members; it is then replaced by Enum's :meth:`__new__` which is used after
+ The :meth:`~object.__new__` method, if defined, is used during creation of the Enum
+ members; it is then replaced by Enum's :meth:`~object.__new__` which is used after
class creation for lookup of existing members.
.. warning::
@@ -1494,7 +1505,7 @@ Supports having more than one value per member::
Planet
^^^^^^
-If :meth:`__new__` or :meth:`__init__` is defined, the value of the enum member
+If :meth:`~object.__new__` or :meth:`~object.__init__` is defined, the value of the enum member
will be passed to those methods::
>>> class Planet(Enum):
@@ -1525,7 +1536,7 @@ will be passed to those methods::
TimePeriod
^^^^^^^^^^
-An example to show the :attr:`_ignore_` attribute in use::
+An example to show the :attr:`~Enum._ignore_` attribute in use::
>>> from datetime import timedelta
>>> class Period(timedelta, Enum):
diff --git a/Doc/howto/free-threading-extensions.rst b/Doc/howto/free-threading-extensions.rst
new file mode 100644
index 00000000000000..6abe93d71ad529
--- /dev/null
+++ b/Doc/howto/free-threading-extensions.rst
@@ -0,0 +1,280 @@
+.. highlight:: c
+
+.. _freethreading-extensions-howto:
+
+******************************************
+C API Extension Support for Free Threading
+******************************************
+
+Starting with the 3.13 release, CPython has experimental support for running
+with the :term:`global interpreter lock` (GIL) disabled in a configuration
+called :term:`free threading`. This document describes how to adapt C API
+extensions to support free threading.
+
+
+Identifying the Free-Threaded Build in C
+========================================
+
+The CPython C API exposes the ``Py_GIL_DISABLED`` macro: in the free-threaded
+build it's defined to ``1``, and in the regular build it's not defined.
+You can use it to enable code that only runs under the free-threaded build::
+
+ #ifdef Py_GIL_DISABLED
+ /* code that only runs in the free-threaded build */
+ #endif
+
+Module Initialization
+=====================
+
+Extension modules need to explicitly indicate that they support running with
+the GIL disabled; otherwise importing the extension will raise a warning and
+enable the GIL at runtime.
+
+There are two ways to indicate that an extension module supports running with
+the GIL disabled depending on whether the extension uses multi-phase or
+single-phase initialization.
+
+Multi-Phase Initialization
+..........................
+
+Extensions that use multi-phase initialization (i.e.,
+:c:func:`PyModuleDef_Init`) should add a :c:data:`Py_mod_gil` slot in the
+module definition. If your extension supports older versions of CPython,
+you should guard the slot with a :c:data:`PY_VERSION_HEX` check.
+
+::
+
+ static struct PyModuleDef_Slot module_slots[] = {
+ ...
+ #if PY_VERSION_HEX >= 0x030D0000
+ {Py_mod_gil, Py_MOD_GIL_NOT_USED},
+ #endif
+ {0, NULL}
+ };
+
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_slots = module_slots,
+ ...
+ };
+
+
+Single-Phase Initialization
+...........................
+
+Extensions that use single-phase initialization (i.e.,
+:c:func:`PyModule_Create`) should call :c:func:`PyUnstable_Module_SetGIL` to
+indicate that they support running with the GIL disabled. The function is
+only defined in the free-threaded build, so you should guard the call with
+``#ifdef Py_GIL_DISABLED`` to avoid compilation errors in the regular build.
+
+::
+
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ ...
+ };
+
+ PyMODINIT_FUNC
+ PyInit_mymodule(void)
+ {
+ PyObject *m = PyModule_Create(&moduledef);
+ if (m == NULL) {
+ return NULL;
+ }
+ #ifdef Py_GIL_DISABLED
+ PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
+ #endif
+ return m;
+ }
+
+
+General API Guidelines
+======================
+
+Most of the C API is thread-safe, but there are some exceptions.
+
+* **Struct Fields**: Accessing fields in Python C API objects or structs
+ directly is not thread-safe if the field may be concurrently modified.
+* **Macros**: Accessor macros like :c:macro:`PyList_GET_ITEM` and
+ :c:macro:`PyList_SET_ITEM` do not perform any error checking or locking.
+ These macros are not thread-safe if the container object may be modified
+ concurrently.
+* **Borrowed References**: C API functions that return
+ :term:`borrowed references ` may not be thread-safe if
+ the containing object is modified concurrently. See the section on
+ :ref:`borrowed references ` for more information.
+
+
+Container Thread Safety
+.......................
+
+Containers like :c:struct:`PyListObject`,
+:c:struct:`PyDictObject`, and :c:struct:`PySetObject` perform internal locking
+in the free-threaded build. For example, the :c:func:`PyList_Append` will
+lock the list before appending an item.
+
+.. _PyDict_Next:
+
+``PyDict_Next``
+'''''''''''''''
+
+A notable exception is :c:func:`PyDict_Next`, which does not lock the
+dictionary. You should use :c:macro:`Py_BEGIN_CRITICAL_SECTION` to protect
+the dictionary while iterating over it if the dictionary may be concurrently
+modified::
+
+ Py_BEGIN_CRITICAL_SECTION(dict);
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ ...
+ }
+ Py_END_CRITICAL_SECTION();
+
+
+Borrowed References
+===================
+
+.. _borrowed-references:
+
+Some C API functions return :term:`borrowed references `.
+These APIs are not thread-safe if the containing object is modified
+concurrently. For example, it's not safe to use :c:func:`PyList_GetItem`
+if the list may be modified concurrently.
+
+The following table lists some borrowed reference APIs and their replacements
+that return :term:`strong references `.
+
++-----------------------------------+-----------------------------------+
+| Borrowed reference API | Strong reference API |
++===================================+===================================+
+| :c:func:`PyList_GetItem` | :c:func:`PyList_GetItemRef` |
++-----------------------------------+-----------------------------------+
+| :c:func:`PyDict_GetItem` | :c:func:`PyDict_GetItemRef` |
++-----------------------------------+-----------------------------------+
+| :c:func:`PyDict_GetItemWithError` | :c:func:`PyDict_GetItemRef` |
++-----------------------------------+-----------------------------------+
+| :c:func:`PyDict_GetItemString` | :c:func:`PyDict_GetItemStringRef` |
++-----------------------------------+-----------------------------------+
+| :c:func:`PyDict_SetDefault` | :c:func:`PyDict_SetDefaultRef` |
++-----------------------------------+-----------------------------------+
+| :c:func:`PyDict_Next` | none (see :ref:`PyDict_Next`) |
++-----------------------------------+-----------------------------------+
+| :c:func:`PyWeakref_GetObject` | :c:func:`PyWeakref_GetRef` |
++-----------------------------------+-----------------------------------+
+| :c:func:`PyWeakref_GET_OBJECT` | :c:func:`PyWeakref_GetRef` |
++-----------------------------------+-----------------------------------+
+| :c:func:`PyImport_AddModule` | :c:func:`PyImport_AddModuleRef` |
++-----------------------------------+-----------------------------------+
+
+Not all APIs that return borrowed references are problematic. For
+example, :c:func:`PyTuple_GetItem` is safe because tuples are immutable.
+Similarly, not all uses of the above APIs are problematic. For example,
+:c:func:`PyDict_GetItem` is often used for parsing keyword argument
+dictionaries in function calls; those keyword argument dictionaries are
+effectively private (not accessible by other threads), so using borrowed
+references in that context is safe.
+
+Some of these functions were added in Python 3.13. You can use the
+`pythoncapi-compat `_ package
+to provide implementations of these functions for older Python versions.
+
+
+.. _free-threaded-memory-allocation:
+
+Memory Allocation APIs
+======================
+
+Python's memory management C API provides functions in three different
+:ref:`allocation domains `: "raw", "mem", and "object".
+For thread-safety, the free-threaded build requires that only Python objects
+are allocated using the object domain, and that all Python object are
+allocated using that domain. This differs from the prior Python versions,
+where this was only a best practice and not a hard requirement.
+
+.. note::
+
+ Search for uses of :c:func:`PyObject_Malloc` in your
+ extension and check that the allocated memory is used for Python objects.
+ Use :c:func:`PyMem_Malloc` to allocate buffers instead of
+ :c:func:`PyObject_Malloc`.
+
+
+Thread State and GIL APIs
+=========================
+
+Python provides a set of functions and macros to manage thread state and the
+GIL, such as:
+
+* :c:func:`PyGILState_Ensure` and :c:func:`PyGILState_Release`
+* :c:func:`PyEval_SaveThread` and :c:func:`PyEval_RestoreThread`
+* :c:macro:`Py_BEGIN_ALLOW_THREADS` and :c:macro:`Py_END_ALLOW_THREADS`
+
+These functions should still be used in the free-threaded build to manage
+thread state even when the :term:`GIL` is disabled. For example, if you
+create a thread outside of Python, you must call :c:func:`PyGILState_Ensure`
+before calling into the Python API to ensure that the thread has a valid
+Python thread state.
+
+You should continue to call :c:func:`PyEval_SaveThread` or
+:c:macro:`Py_BEGIN_ALLOW_THREADS` around blocking operations, such as I/O or
+lock acquisitions, to allow other threads to run the
+:term:`cyclic garbage collector `.
+
+
+Protecting Internal Extension State
+===================================
+
+Your extension may have internal state that was previously protected by the
+GIL. You may need to add locking to protect this state. The approach will
+depend on your extension, but some common patterns include:
+
+* **Caches**: global caches are a common source of shared state. Consider
+ using a lock to protect the cache or disabling it in the free-threaded build
+ if the cache is not critical for performance.
+* **Global State**: global state may need to be protected by a lock or moved
+ to thread local storage. C11 and C++11 provide the ``thread_local`` or
+ ``_Thread_local`` for
+ `thread-local storage `_.
+
+
+Building Extensions for the Free-Threaded Build
+===============================================
+
+C API extensions need to be built specifically for the free-threaded build.
+The wheels, shared libraries, and binaries are indicated by a ``t`` suffix.
+
+* `pypa/manylinux `_ supports the
+ free-threaded build, with the ``t`` suffix, such as ``python3.13t``.
+* `pypa/cibuildwheel `_ supports the
+ free-threaded build if you set
+ `CIBW_FREE_THREADED_SUPPORT `_.
+
+Limited C API and Stable ABI
+............................
+
+The free-threaded build does not currently support the
+:ref:`Limited C API ` or the stable ABI. If you use
+`setuptools `_ to build
+your extension and currently set ``py_limited_api=True`` you can use
+``py_limited_api=not sysconfig.get_config_var("Py_GIL_DISABLED")`` to opt out
+of the limited API when building with the free-threaded build.
+
+.. note::
+ You will need to build separate wheels specifically for the free-threaded
+ build. If you currently use the stable ABI, you can continue to build a
+ single wheel for multiple non-free-threaded Python versions.
+
+
+Windows
+.......
+
+Due to a limitation of the official Windows installer, you will need to
+manually define ``Py_GIL_DISABLED=1`` when building extensions from source.
+
+.. seealso::
+
+ `Porting Extension Modules to Support Free-Threading
+ `_:
+ A community-maintained porting guide for extension authors.
diff --git a/Doc/howto/free-threading-python.rst b/Doc/howto/free-threading-python.rst
new file mode 100644
index 00000000000000..cd920553a3a461
--- /dev/null
+++ b/Doc/howto/free-threading-python.rst
@@ -0,0 +1,154 @@
+.. _freethreading-python-howto:
+
+**********************************************
+Python experimental support for free threading
+**********************************************
+
+Starting with the 3.13 release, CPython has experimental support for a build of
+Python called :term:`free threading` where the :term:`global interpreter lock`
+(GIL) is disabled. Free-threaded execution allows for full utilization of the
+available processing power by running threads in parallel on available CPU cores.
+While not all software will benefit from this automatically, programs
+designed with threading in mind will run faster on multi-core hardware.
+
+**The free-threaded mode is experimental** and work is ongoing to improve it:
+expect some bugs and a substantial single-threaded performance hit.
+
+This document describes the implications of free threading
+for Python code. See :ref:`freethreading-extensions-howto` for information on
+how to write C extensions that support the free-threaded build.
+
+.. seealso::
+
+ :pep:`703` – Making the Global Interpreter Lock Optional in CPython for an
+ overall description of free-threaded Python.
+
+
+Installation
+============
+
+Starting with Python 3.13, the official macOS and Windows installers
+optionally support installing free-threaded Python binaries. The installers
+are available at https://www.python.org/downloads/.
+
+For information on other platforms, see the `Installing a Free-Threaded Python
+`_, a
+community-maintained installation guide for installing free-threaded Python.
+
+When building CPython from source, the :option:`--disable-gil` configure option
+should be used to build a free-threaded Python interpreter.
+
+
+Identifying free-threaded Python
+================================
+
+To check if the current interpreter supports free-threading, :option:`python -VV <-V>`
+and :data:`sys.version` contain "experimental free-threading build".
+The new :func:`sys._is_gil_enabled` function can be used to check whether
+the GIL is actually disabled in the running process.
+
+The ``sysconfig.get_config_var("Py_GIL_DISABLED")`` configuration variable can
+be used to determine whether the build supports free threading. If the variable
+is set to ``1``, then the build supports free threading. This is the recommended
+mechanism for decisions related to the build configuration.
+
+
+The global interpreter lock in free-threaded Python
+===================================================
+
+Free-threaded builds of CPython support optionally running with the GIL enabled
+at runtime using the environment variable :envvar:`PYTHON_GIL` or
+the command-line option :option:`-X gil`.
+
+The GIL may also automatically be enabled when importing a C-API extension
+module that is not explicitly marked as supporting free threading. A warning
+will be printed in this case.
+
+In addition to individual package documentation, the following websites track
+the status of popular packages support for free threading:
+
+* https://py-free-threading.github.io/tracking/
+* https://hugovk.github.io/free-threaded-wheels/
+
+
+Thread safety
+=============
+
+The free-threaded build of CPython aims to provide similar thread-safety
+behavior at the Python level to the default GIL-enabled build. Built-in
+types like :class:`dict`, :class:`list`, and :class:`set` use internal locks
+to protect against concurrent modifications in ways that behave similarly to
+the GIL. However, Python has not historically guaranteed specific behavior for
+concurrent modifications to these built-in types, so this should be treated
+as a description of the current implementation, not a guarantee of current or
+future behavior.
+
+.. note::
+
+ It's recommended to use the :class:`threading.Lock` or other synchronization
+ primitives instead of relying on the internal locks of built-in types, when
+ possible.
+
+
+Known limitations
+=================
+
+This section describes known limitations of the free-threaded CPython build.
+
+Immortalization
+---------------
+
+The free-threaded build of the 3.13 release makes some objects :term:`immortal`.
+Immortal objects are not deallocated and have reference counts that are
+never modified. This is done to avoid reference count contention that would
+prevent efficient multi-threaded scaling.
+
+An object will be made immortal when a new thread is started for the first time
+after the main thread is running. The following objects are immortalized:
+
+* :ref:`function ` objects declared at the module level
+* :ref:`method ` descriptors
+* :ref:`code ` objects
+* :term:`module` objects and their dictionaries
+* :ref:`classes ` (type objects)
+
+Because immortal objects are never deallocated, applications that create many
+objects of these types may see increased memory usage. This is expected to be
+addressed in the 3.14 release.
+
+Additionally, numeric and string literals in the code as well as strings
+returned by :func:`sys.intern` are also immortalized. This behavior is
+expected to remain in the 3.14 free-threaded build.
+
+
+Frame objects
+-------------
+
+It is not safe to access :ref:`frame ` objects from other
+threads and doing so may cause your program to crash . This means that
+:func:`sys._current_frames` is generally not safe to use in a free-threaded
+build. Functions like :func:`inspect.currentframe` and :func:`sys._getframe`
+are generally safe as long as the resulting frame object is not passed to
+another thread.
+
+Iterators
+---------
+
+Sharing the same iterator object between multiple threads is generally not
+safe and threads may see duplicate or missing elements when iterating or crash
+the interpreter.
+
+
+Single-threaded performance
+---------------------------
+
+The free-threaded build has additional overhead when executing Python code
+compared to the default GIL-enabled build. In 3.13, this overhead is about
+40% on the `pyperformance `_ suite.
+Programs that spend most of their time in C extensions or I/O will see
+less of an impact. The largest impact is because the specializing adaptive
+interpreter (:pep:`659`) is disabled in the free-threaded build. We expect
+to re-enable it in a thread-safe way in the 3.14 release. This overhead is
+expected to be reduced in upcoming Python release. We are aiming for an
+overhead of 10% or less on the pyperformance suite compared to the default
+GIL-enabled build.
diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst
index b0f9d22d74f0e3..1f0608fb0fc53f 100644
--- a/Doc/howto/functional.rst
+++ b/Doc/howto/functional.rst
@@ -1,3 +1,5 @@
+.. _functional-howto:
+
********************************
Functional Programming HOWTO
********************************
diff --git a/Doc/howto/gdb_helpers.rst b/Doc/howto/gdb_helpers.rst
index 53bbf7ddaa2ab9..98ce813ca4ab02 100644
--- a/Doc/howto/gdb_helpers.rst
+++ b/Doc/howto/gdb_helpers.rst
@@ -180,7 +180,7 @@ regular machine-level integer::
(gdb) p some_python_integer
$4 = 42
-The internal structure can be revealed with a cast to :c:expr:`PyLongObject *`:
+The internal structure can be revealed with a cast to :c:expr:`PyLongObject *`::
(gdb) p *(PyLongObject*)some_python_integer
$5 = {ob_base = {ob_base = {ob_refcnt = 8, ob_type = 0x3dad39f5e0}, ob_size = 1},
diff --git a/Doc/howto/index.rst b/Doc/howto/index.rst
index 065071e39a06c5..c09f92c9528ee1 100644
--- a/Doc/howto/index.rst
+++ b/Doc/howto/index.rst
@@ -2,16 +2,14 @@
Python HOWTOs
***************
-Python HOWTOs are documents that cover a single, specific topic,
-and attempt to cover it fairly completely. Modelled on the Linux
-Documentation Project's HOWTO collection, this collection is an
+Python HOWTOs are documents that cover a specific topic in-depth.
+Modeled on the Linux Documentation Project's HOWTO collection, this collection is an
effort to foster documentation that's more detailed than the
Python Library Reference.
-Currently, the HOWTOs are:
-
.. toctree::
:maxdepth: 1
+ :hidden:
cporting.rst
curses.rst
@@ -34,4 +32,37 @@ Currently, the HOWTOs are:
isolating-extensions.rst
timerfd.rst
mro.rst
+ free-threading-python.rst
+ free-threading-extensions.rst
+
+General:
+
+* :ref:`annotations-howto`
+* :ref:`argparse-tutorial`
+* :ref:`descriptorhowto`
+* :ref:`enum-howto`
+* :ref:`functional-howto`
+* :ref:`ipaddress-howto`
+* :ref:`logging-howto`
+* :ref:`logging-cookbook`
+* :ref:`regex-howto`
+* :ref:`sortinghowto`
+* :ref:`unicode-howto`
+* :ref:`urllib-howto`
+
+Advanced development:
+
+* :ref:`curses-howto`
+* :ref:`freethreading-python-howto`
+* :ref:`freethreading-extensions-howto`
+* :ref:`isolating-extensions-howto`
+* :ref:`python_2.3_mro`
+* :ref:`socket-howto`
+* :ref:`timerfd-howto`
+* :ref:`cporting-howto`
+
+Debugging and profiling:
+* :ref:`gdb`
+* :ref:`instrumentation`
+* :ref:`perf_profiling`
diff --git a/Doc/howto/instrumentation.rst b/Doc/howto/instrumentation.rst
index 9c99fcecce1fcb..6e03ef20a21fa3 100644
--- a/Doc/howto/instrumentation.rst
+++ b/Doc/howto/instrumentation.rst
@@ -307,7 +307,7 @@ Available static markers
.. object:: gc__start(int generation)
Fires when the Python interpreter starts a garbage collection cycle.
- ``arg0`` is the generation to scan, like :func:`gc.collect()`.
+ ``arg0`` is the generation to scan, like :func:`gc.collect`.
.. object:: gc__done(long collected)
diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst
index e35855deedbe5f..a636e06bda8344 100644
--- a/Doc/howto/isolating-extensions.rst
+++ b/Doc/howto/isolating-extensions.rst
@@ -339,7 +339,7 @@ That is, heap types should:
- Define a traverse function using ``Py_tp_traverse``, which
visits the type (e.g. using ``Py_VISIT(Py_TYPE(self))``).
-Please refer to the the documentation of
+Please refer to the documentation of
:c:macro:`Py_TPFLAGS_HAVE_GC` and :c:member:`~PyTypeObject.tp_traverse`
for additional considerations.
diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst
index 60d88204b795f6..17fc4619db327a 100644
--- a/Doc/howto/logging-cookbook.rst
+++ b/Doc/howto/logging-cookbook.rst
@@ -825,9 +825,9 @@ To test these files, do the following in a POSIX environment:
which will lead to records being written to the log.
#. Inspect the log files in the :file:`run` subdirectory. You should see the
- most recent log lines in files matching the pattern :file:`app.log*`. They won't be in
- any particular order, since they have been handled concurrently by different
- worker processes in a non-deterministic way.
+ most recent log lines in files matching the pattern :file:`app.log*`. They
+ won't be in any particular order, since they have been handled concurrently
+ by different worker processes in a non-deterministic way.
#. You can shut down the listener and the web application by running
``venv/bin/supervisorctl -c supervisor.conf shutdown``.
@@ -835,6 +835,19 @@ To test these files, do the following in a POSIX environment:
You may need to tweak the configuration files in the unlikely event that the
configured ports clash with something else in your test environment.
+The default configuration uses a TCP socket on port 9020. You can use a Unix
+Domain socket instead of a TCP socket by doing the following:
+
+#. In :file:`listener.json`, add a ``socket`` key with the path to the domain
+ socket you want to use. If this key is present, the listener listens on the
+ corresponding domain socket and not on a TCP socket (the ``port`` key is
+ ignored).
+
+#. In :file:`webapp.json`, change the socket handler configuration dictionary
+ so that the ``host`` value is the path to the domain socket, and set the
+ ``port`` value to ``null``.
+
+
.. currentmodule:: logging
.. _context-info:
@@ -1267,11 +1280,8 @@ to adapt in your own applications.
You could also write your own handler which uses the :class:`~multiprocessing.Lock`
class from the :mod:`multiprocessing` module to serialize access to the
-file from your processes. The existing :class:`FileHandler` and subclasses do
-not make use of :mod:`multiprocessing` at present, though they may do so in the
-future. Note that at present, the :mod:`multiprocessing` module does not provide
-working lock functionality on all platforms (see
-https://bugs.python.org/issue3770).
+file from your processes. The stdlib :class:`FileHandler` and subclasses do
+not make use of :mod:`multiprocessing`.
.. currentmodule:: logging.handlers
@@ -4022,7 +4032,7 @@ As you can see, this output isn't ideal. That's because the underlying code
which writes to ``sys.stderr`` makes multiple writes, each of which results in a
separate logged line (for example, the last three lines above). To get around
this problem, you need to buffer things and only output log lines when newlines
-are seen. Let's use a slghtly better implementation of ``LoggerWriter``:
+are seen. Let's use a slightly better implementation of ``LoggerWriter``:
.. code-block:: python
diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst
index ab758a885b3556..3182d5664ab6ec 100644
--- a/Doc/howto/logging.rst
+++ b/Doc/howto/logging.rst
@@ -1,3 +1,5 @@
+.. _logging-howto:
+
=============
Logging HOWTO
=============
@@ -380,8 +382,52 @@ Logging Flow
The flow of log event information in loggers and handlers is illustrated in the
following diagram.
-.. image:: logging_flow.png
- :class: invert-in-dark-mode
+.. only:: not html
+
+ .. image:: logging_flow.*
+
+.. raw:: html
+ :file: logging_flow.svg
+
+.. raw:: html
+
+
Loggers
^^^^^^^
diff --git a/Doc/howto/logging_flow.png b/Doc/howto/logging_flow.png
index d65e597f811db5..d60ed7c031585a 100644
Binary files a/Doc/howto/logging_flow.png and b/Doc/howto/logging_flow.png differ
diff --git a/Doc/howto/logging_flow.svg b/Doc/howto/logging_flow.svg
new file mode 100644
index 00000000000000..4974994ac6b400
--- /dev/null
+++ b/Doc/howto/logging_flow.svg
@@ -0,0 +1,327 @@
+
diff --git a/Doc/howto/mro.rst b/Doc/howto/mro.rst
index a44ef6848af4f3..0872bedcd3a2d3 100644
--- a/Doc/howto/mro.rst
+++ b/Doc/howto/mro.rst
@@ -335,7 +335,7 @@ E is more specialized than C, even if it is in a higher level.
A lazy programmer can obtain the MRO directly from Python 2.2, since in
this case it coincides with the Python 2.3 linearization. It is enough
-to invoke the .mro() method of class A:
+to invoke the :meth:`~type.mro` method of class A:
>>> A.mro() # doctest: +NORMALIZE_WHITESPACE
[, , ,
@@ -398,7 +398,7 @@ with inheritance diagram
We see that class G inherits from F and E, with F *before* E: therefore
we would expect the attribute *G.remember2buy* to be inherited by
-*F.rembermer2buy* and not by *E.remember2buy*: nevertheless Python 2.2
+*F.remember2buy* and not by *E.remember2buy*: nevertheless Python 2.2
gives
>>> G.remember2buy # doctest: +SKIP
@@ -426,7 +426,7 @@ In this case the MRO is GFEF and the local precedence ordering is
preserved.
As a general rule, hierarchies such as the previous one should be
-avoided, since it is unclear if F should override E or viceversa.
+avoided, since it is unclear if F should override E or vice-versa.
Python 2.3 solves the ambiguity by raising an exception in the creation
of class G, effectively stopping the programmer from generating
ambiguous hierarchies. The reason for that is that the C3 algorithm
diff --git a/Doc/howto/perf_profiling.rst b/Doc/howto/perf_profiling.rst
index 06459d1b222964..b579d776576365 100644
--- a/Doc/howto/perf_profiling.rst
+++ b/Doc/howto/perf_profiling.rst
@@ -162,12 +162,12 @@ the :option:`!-X` option takes precedence over the environment variable.
Example, using the environment variable::
- $ PYTHONPERFSUPPORT=1 perf record -F 9999 -g -o perf.data python script.py
+ $ PYTHONPERFSUPPORT=1 perf record -F 9999 -g -o perf.data python my_script.py
$ perf report -g -i perf.data
Example, using the :option:`!-X` option::
- $ perf record -F 9999 -g -o perf.data python -X perf script.py
+ $ perf record -F 9999 -g -o perf.data python -X perf my_script.py
$ perf report -g -i perf.data
Example, using the :mod:`sys` APIs in file :file:`example.py`:
@@ -236,7 +236,7 @@ When using the perf JIT mode, you need an extra step before you can run ``perf
report``. You need to call the ``perf inject`` command to inject the JIT
information into the ``perf.data`` file.::
- $ perf record -F 9999 -g --call-graph dwarf -o perf.data python -Xperf_jit my_script.py
+ $ perf record -F 9999 -g -k 1 --call-graph dwarf -o perf.data python -Xperf_jit my_script.py
$ perf inject -i perf.data --jit --output perf.jit.data
$ perf report -g -i perf.jit.data
@@ -254,13 +254,28 @@ files in the current directory which are ELF images for all the JIT trampolines
that were created by Python.
.. warning::
- Notice that when using ``--call-graph dwarf`` the ``perf`` tool will take
+ When using ``--call-graph dwarf``, the ``perf`` tool will take
snapshots of the stack of the process being profiled and save the
- information in the ``perf.data`` file. By default the size of the stack dump
- is 8192 bytes but the user can change the size by passing the size after
- comma like ``--call-graph dwarf,4096``. The size of the stack dump is
- important because if the size is too small ``perf`` will not be able to
- unwind the stack and the output will be incomplete. On the other hand, if
- the size is too big, then ``perf`` won't be able to sample the process as
- frequently as it would like as the overhead will be higher.
+ information in the ``perf.data`` file. By default, the size of the stack dump
+ is 8192 bytes, but you can change the size by passing it after
+ a comma like ``--call-graph dwarf,16384``.
+ The size of the stack dump is important because if the size is too small
+ ``perf`` will not be able to unwind the stack and the output will be
+ incomplete. On the other hand, if the size is too big, then ``perf`` won't
+ be able to sample the process as frequently as it would like as the overhead
+ will be higher.
+
+ The stack size is particularly important when profiling Python code compiled
+ with low optimization levels (like ``-O0``), as these builds tend to have
+ larger stack frames. If you are compiling Python with ``-O0`` and not seeing
+ Python functions in your profiling output, try increasing the stack dump
+ size to 65528 bytes (the maximum)::
+
+ $ perf record -F 9999 -g -k 1 --call-graph dwarf,65528 -o perf.data python -Xperf_jit my_script.py
+
+ Different compilation flags can significantly impact stack sizes:
+
+ - Builds with ``-O0`` typically have much larger stack frames than those with ``-O1`` or higher
+ - Adding optimizations (``-O1``, ``-O2``, etc.) typically reduces stack size
+ - Frame pointers (``-fno-omit-frame-pointer``) generally provide more reliable stack unwinding
diff --git a/Doc/howto/pyporting.rst b/Doc/howto/pyporting.rst
index d560364107bd12..9f73c811cfcbc0 100644
--- a/Doc/howto/pyporting.rst
+++ b/Doc/howto/pyporting.rst
@@ -18,9 +18,9 @@ please see :ref:`cporting-howto`.
The archived python-porting_ mailing list may contain some useful guidance.
-Since Python 3.13 the original porting guide was discontinued.
+Since Python 3.11 the original porting guide was discontinued.
You can find the old guide in the
-`archive `_.
+`archive `_.
Third-party guides
diff --git a/Doc/includes/email-alternative.py b/Doc/includes/email-alternative.py
index 26b302b495c7ac..afe2b4fbb5eb3f 100644
--- a/Doc/includes/email-alternative.py
+++ b/Doc/includes/email-alternative.py
@@ -36,7 +36,7 @@
recette
sera sûrement un très bon repas.
-
+