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

- + """.format(asparagus_cid=asparagus_cid[1:-1]), subtype='html') diff --git a/Doc/includes/newtypes/custom2.c b/Doc/includes/newtypes/custom2.c index 768ce29fab9ff0..a87917583ca495 100644 --- a/Doc/includes/newtypes/custom2.c +++ b/Doc/includes/newtypes/custom2.c @@ -10,11 +10,12 @@ typedef struct { } CustomObject; static void -Custom_dealloc(CustomObject *self) +Custom_dealloc(PyObject *op) { + CustomObject *self = (CustomObject *) op; Py_XDECREF(self->first); Py_XDECREF(self->last); - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free(self); } static PyObject * @@ -39,8 +40,9 @@ Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } static int -Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) +Custom_init(PyObject *op, PyObject *args, PyObject *kwds) { + CustomObject *self = (CustomObject *) op; static char *kwlist[] = {"first", "last", "number", NULL}; PyObject *first = NULL, *last = NULL; @@ -69,8 +71,9 @@ static PyMemberDef Custom_members[] = { }; static PyObject * -Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) +Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy)) { + CustomObject *self = (CustomObject *) op; if (self->first == NULL) { PyErr_SetString(PyExc_AttributeError, "first"); return NULL; @@ -83,7 +86,7 @@ Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) } static PyMethodDef Custom_methods[] = { - {"name", (PyCFunction) Custom_name, METH_NOARGS, + {"name", Custom_name, METH_NOARGS, "Return the name, combining the first and last name" }, {NULL} /* Sentinel */ @@ -97,8 +100,8 @@ static PyTypeObject CustomType = { .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_new = Custom_new, - .tp_init = (initproc) Custom_init, - .tp_dealloc = (destructor) Custom_dealloc, + .tp_init = Custom_init, + .tp_dealloc = Custom_dealloc, .tp_members = Custom_members, .tp_methods = Custom_methods, }; diff --git a/Doc/includes/newtypes/custom3.c b/Doc/includes/newtypes/custom3.c index 7d969adfa7c9cc..854034d4066d20 100644 --- a/Doc/includes/newtypes/custom3.c +++ b/Doc/includes/newtypes/custom3.c @@ -10,11 +10,12 @@ typedef struct { } CustomObject; static void -Custom_dealloc(CustomObject *self) +Custom_dealloc(PyObject *op) { + CustomObject *self = (CustomObject *) op; Py_XDECREF(self->first); Py_XDECREF(self->last); - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free(self); } static PyObject * @@ -39,8 +40,9 @@ Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } static int -Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) +Custom_init(PyObject *op, PyObject *args, PyObject *kwds) { + CustomObject *self = (CustomObject *) op; static char *kwlist[] = {"first", "last", "number", NULL}; PyObject *first = NULL, *last = NULL; @@ -65,14 +67,16 @@ static PyMemberDef Custom_members[] = { }; static PyObject * -Custom_getfirst(CustomObject *self, void *closure) +Custom_getfirst(PyObject *op, void *closure) { + CustomObject *self = (CustomObject *) op; return Py_NewRef(self->first); } static int -Custom_setfirst(CustomObject *self, PyObject *value, void *closure) +Custom_setfirst(PyObject *op, PyObject *value, void *closure) { + CustomObject *self = (CustomObject *) op; if (value == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); return -1; @@ -87,14 +91,16 @@ Custom_setfirst(CustomObject *self, PyObject *value, void *closure) } static PyObject * -Custom_getlast(CustomObject *self, void *closure) +Custom_getlast(PyObject *op, void *closure) { + CustomObject *self = (CustomObject *) op; return Py_NewRef(self->last); } static int -Custom_setlast(CustomObject *self, PyObject *value, void *closure) +Custom_setlast(PyObject *op, PyObject *value, void *closure) { + CustomObject *self = (CustomObject *) op; if (value == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); return -1; @@ -109,21 +115,22 @@ Custom_setlast(CustomObject *self, PyObject *value, void *closure) } static PyGetSetDef Custom_getsetters[] = { - {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, + {"first", Custom_getfirst, Custom_setfirst, "first name", NULL}, - {"last", (getter) Custom_getlast, (setter) Custom_setlast, + {"last", Custom_getlast, Custom_setlast, "last name", NULL}, {NULL} /* Sentinel */ }; static PyObject * -Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) +Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy)) { + CustomObject *self = (CustomObject *) op; return PyUnicode_FromFormat("%S %S", self->first, self->last); } static PyMethodDef Custom_methods[] = { - {"name", (PyCFunction) Custom_name, METH_NOARGS, + {"name", Custom_name, METH_NOARGS, "Return the name, combining the first and last name" }, {NULL} /* Sentinel */ @@ -137,8 +144,8 @@ static PyTypeObject CustomType = { .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_new = Custom_new, - .tp_init = (initproc) Custom_init, - .tp_dealloc = (destructor) Custom_dealloc, + .tp_init = Custom_init, + .tp_dealloc = Custom_dealloc, .tp_members = Custom_members, .tp_methods = Custom_methods, .tp_getset = Custom_getsetters, diff --git a/Doc/includes/newtypes/custom4.c b/Doc/includes/newtypes/custom4.c index a7b8de44a57c90..a0a1eeb289190b 100644 --- a/Doc/includes/newtypes/custom4.c +++ b/Doc/includes/newtypes/custom4.c @@ -10,27 +10,29 @@ typedef struct { } CustomObject; static int -Custom_traverse(CustomObject *self, visitproc visit, void *arg) +Custom_traverse(PyObject *op, visitproc visit, void *arg) { + CustomObject *self = (CustomObject *) op; Py_VISIT(self->first); Py_VISIT(self->last); return 0; } static int -Custom_clear(CustomObject *self) +Custom_clear(PyObject *op) { + CustomObject *self = (CustomObject *) op; Py_CLEAR(self->first); Py_CLEAR(self->last); return 0; } static void -Custom_dealloc(CustomObject *self) +Custom_dealloc(PyObject *op) { - PyObject_GC_UnTrack(self); - Custom_clear(self); - Py_TYPE(self)->tp_free((PyObject *) self); + PyObject_GC_UnTrack(op); + (void)Custom_clear(op); + Py_TYPE(op)->tp_free(op); } static PyObject * @@ -55,8 +57,9 @@ Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } static int -Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) +Custom_init(PyObject *op, PyObject *args, PyObject *kwds) { + CustomObject *self = (CustomObject *) op; static char *kwlist[] = {"first", "last", "number", NULL}; PyObject *first = NULL, *last = NULL; @@ -81,14 +84,16 @@ static PyMemberDef Custom_members[] = { }; static PyObject * -Custom_getfirst(CustomObject *self, void *closure) +Custom_getfirst(PyObject *op, void *closure) { + CustomObject *self = (CustomObject *) op; return Py_NewRef(self->first); } static int -Custom_setfirst(CustomObject *self, PyObject *value, void *closure) +Custom_setfirst(PyObject *op, PyObject *value, void *closure) { + CustomObject *self = (CustomObject *) op; if (value == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); return -1; @@ -103,14 +108,16 @@ Custom_setfirst(CustomObject *self, PyObject *value, void *closure) } static PyObject * -Custom_getlast(CustomObject *self, void *closure) +Custom_getlast(PyObject *op, void *closure) { + CustomObject *self = (CustomObject *) op; return Py_NewRef(self->last); } static int -Custom_setlast(CustomObject *self, PyObject *value, void *closure) +Custom_setlast(PyObject *op, PyObject *value, void *closure) { + CustomObject *self = (CustomObject *) op; if (value == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); return -1; @@ -125,21 +132,22 @@ Custom_setlast(CustomObject *self, PyObject *value, void *closure) } static PyGetSetDef Custom_getsetters[] = { - {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, + {"first", Custom_getfirst, Custom_setfirst, "first name", NULL}, - {"last", (getter) Custom_getlast, (setter) Custom_setlast, + {"last", Custom_getlast, Custom_setlast, "last name", NULL}, {NULL} /* Sentinel */ }; static PyObject * -Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) +Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy)) { + CustomObject *self = (CustomObject *) op; return PyUnicode_FromFormat("%S %S", self->first, self->last); } static PyMethodDef Custom_methods[] = { - {"name", (PyCFunction) Custom_name, METH_NOARGS, + {"name", Custom_name, METH_NOARGS, "Return the name, combining the first and last name" }, {NULL} /* Sentinel */ @@ -153,10 +161,10 @@ static PyTypeObject CustomType = { .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, .tp_new = Custom_new, - .tp_init = (initproc) Custom_init, - .tp_dealloc = (destructor) Custom_dealloc, - .tp_traverse = (traverseproc) Custom_traverse, - .tp_clear = (inquiry) Custom_clear, + .tp_init = Custom_init, + .tp_dealloc = Custom_dealloc, + .tp_traverse = Custom_traverse, + .tp_clear = Custom_clear, .tp_members = Custom_members, .tp_methods = Custom_methods, .tp_getset = Custom_getsetters, diff --git a/Doc/includes/newtypes/sublist.c b/Doc/includes/newtypes/sublist.c index d8aba463f30ba2..00664f3454156f 100644 --- a/Doc/includes/newtypes/sublist.c +++ b/Doc/includes/newtypes/sublist.c @@ -7,22 +7,24 @@ typedef struct { } SubListObject; static PyObject * -SubList_increment(SubListObject *self, PyObject *unused) +SubList_increment(PyObject *op, PyObject *Py_UNUSED(dummy)) { + SubListObject *self = (SubListObject *) op; self->state++; return PyLong_FromLong(self->state); } static PyMethodDef SubList_methods[] = { - {"increment", (PyCFunction) SubList_increment, METH_NOARGS, + {"increment", SubList_increment, METH_NOARGS, PyDoc_STR("increment state counter")}, {NULL}, }; static int -SubList_init(SubListObject *self, PyObject *args, PyObject *kwds) +SubList_init(PyObject *op, PyObject *args, PyObject *kwds) { - if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0) + SubListObject *self = (SubListObject *) op; + if (PyList_Type.tp_init(op, args, kwds) < 0) return -1; self->state = 0; return 0; @@ -35,7 +37,7 @@ static PyTypeObject SubListType = { .tp_basicsize = sizeof(SubListObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_init = (initproc) SubList_init, + .tp_init = SubList_init, .tp_methods = SubList_methods, }; diff --git a/Doc/includes/typestruct.h b/Doc/includes/typestruct.h index ec939c28831c33..0d1d85ce9741b2 100644 --- a/Doc/includes/typestruct.h +++ b/Doc/includes/typestruct.h @@ -54,11 +54,11 @@ typedef struct _typeobject { iternextfunc tp_iternext; /* Attribute descriptor and subclassing stuff */ - struct PyMethodDef *tp_methods; - struct PyMemberDef *tp_members; - struct PyGetSetDef *tp_getset; + PyMethodDef *tp_methods; + PyMemberDef *tp_members; + PyGetSetDef *tp_getset; // Strong reference on a heap type, borrowed reference on a static type - struct _typeobject *tp_base; + PyTypeObject *tp_base; PyObject *tp_dict; descrgetfunc tp_descr_get; descrsetfunc tp_descr_set; @@ -70,12 +70,14 @@ typedef struct _typeobject { inquiry tp_is_gc; /* For PyObject_IS_GC */ PyObject *tp_bases; PyObject *tp_mro; /* method resolution order */ - PyObject *tp_cache; - PyObject *tp_subclasses; - PyObject *tp_weaklist; + PyObject *tp_cache; /* no longer used */ + void *tp_subclasses; /* for static builtin types this is an index */ + PyObject *tp_weaklist; /* not used for static builtin types */ destructor tp_del; - /* Type attribute cache version tag. Added in version 2.6 */ + /* Type attribute cache version tag. Added in version 2.6. + * If zero, the cache is invalid and must be initialized. + */ unsigned int tp_version_tag; destructor tp_finalize; @@ -83,4 +85,11 @@ typedef struct _typeobject { /* bitset of which type-watchers care about this type */ unsigned char tp_watched; + + /* Number of tp_version_tag values used. + * Set to _Py_ATTR_CACHE_UNUSED if the attribute cache is + * disabled for this type (e.g. due to custom MRO entries). + * Otherwise, limited to MAX_VERSIONS_PER_CLASS (defined elsewhere). + */ + uint16_t tp_versions_used; } PyTypeObject; diff --git a/Doc/library/abc.rst b/Doc/library/abc.rst index 38d744e97d087d..49e541a9d9b1cb 100644 --- a/Doc/library/abc.rst +++ b/Doc/library/abc.rst @@ -141,18 +141,18 @@ a helper class :class:`ABC` to alternatively define ABCs through inheritance: MyIterable.register(Foo) The ABC ``MyIterable`` defines the standard iterable method, - :meth:`~iterator.__iter__`, as an abstract method. The implementation given + :meth:`~object.__iter__`, as an abstract method. The implementation given here can still be called from subclasses. The :meth:`!get_iterator` method is also part of the ``MyIterable`` abstract base class, but it does not have to be overridden in non-abstract derived classes. The :meth:`__subclasshook__` class method defined here says that any class - that has an :meth:`~iterator.__iter__` method in its + that has an :meth:`~object.__iter__` method in its :attr:`~object.__dict__` (or in that of one of its base classes, accessed via the :attr:`~type.__mro__` list) is considered a ``MyIterable`` too. Finally, the last line makes ``Foo`` a virtual subclass of ``MyIterable``, - even though it does not define an :meth:`~iterator.__iter__` method (it uses + even though it does not define an :meth:`~object.__iter__` method (it uses the old-style iterable protocol, defined in terms of :meth:`~object.__len__` and :meth:`~object.__getitem__`). Note that this will not make ``get_iterator`` available as a method of ``Foo``, so it is provided separately. diff --git a/Doc/library/annotationlib.rst b/Doc/library/annotationlib.rst index dcaff3d7fdbec5..41c9ce479ff0f8 100644 --- a/Doc/library/annotationlib.rst +++ b/Doc/library/annotationlib.rst @@ -40,7 +40,7 @@ The :func:`get_annotations` function is the main entry point for retrieving annotations. Given a function, class, or module, it returns an annotations dictionary in the requested format. This module also provides functionality for working directly with the :term:`annotate function` -that is used to evaluate annotations, such as :func:`get_annotate_function` +that is used to evaluate annotations, such as :func:`get_annotate_from_class_namespace` and :func:`call_annotate_function`, as well as the :func:`call_evaluate_function` function for working with :term:`evaluate functions `. @@ -127,16 +127,27 @@ Classes Values are the result of evaluating the annotation expressions. - .. attribute:: FORWARDREF + .. attribute:: VALUE_WITH_FAKE_GLOBALS :value: 2 + Special value used to signal that an annotate function is being + evaluated in a special environment with fake globals. When passed this + value, annotate functions should either return the same value as for + the :attr:`Format.VALUE` format, or raise :exc:`NotImplementedError` + to signal that they do not support execution in this environment. + This format is only used internally and should not be passed to + the functions in this module. + + .. attribute:: FORWARDREF + :value: 3 + Values are real annotation values (as per :attr:`Format.VALUE` format) for defined values, and :class:`ForwardRef` proxies for undefined - values. Real objects may contain references to, :class:`ForwardRef` + values. Real objects may contain references to :class:`ForwardRef` proxy objects. .. attribute:: STRING - :value: 3 + :value: 4 Values are the text string of the annotation as it appears in the source code, up to modifications including, but not restricted to, @@ -144,17 +155,6 @@ Classes The exact values of these strings may change in future versions of Python. - .. attribute:: VALUE_WITH_FAKE_GLOBALS - :value: 4 - - Special value used to signal that an annotate function is being - evaluated in a special environment with fake globals. When passed this - value, annotate functions should either return the same value as for - the :attr:`Format.VALUE` format, or raise :exc:`NotImplementedError` - to signal that they do not support execution in this environment. - This format is only used internally and should not be passed to - the functions in this module. - .. versionadded:: 3.14 .. class:: ForwardRef @@ -172,14 +172,37 @@ Classes :class:`~ForwardRef`. The string may not be exactly equivalent to the original source. - .. method:: evaluate(*, globals=None, locals=None, type_params=None, owner=None) + .. method:: evaluate(*, owner=None, globals=None, locals=None, type_params=None, format=Format.VALUE) Evaluate the forward reference, returning its value. - This may throw an exception, such as :exc:`NameError`, if the forward - reference refers to names that do not exist. The arguments to this + If the *format* argument is :attr:`~Format.VALUE` (the default), + this method may throw an exception, such as :exc:`NameError`, if the forward + reference refers to a name that cannot be resolved. The arguments to this method can be used to provide bindings for names that would otherwise - be undefined. + be undefined. If the *format* argument is :attr:`~Format.FORWARDREF`, + the method will never throw an exception, but may return a :class:`~ForwardRef` + instance. For example, if the forward reference object contains the code + ``list[undefined]``, where ``undefined`` is a name that is not defined, + evaluating it with the :attr:`~Format.FORWARDREF` format will return + ``list[ForwardRef('undefined')]``. If the *format* argument is + :attr:`~Format.STRING`, the method will return :attr:`~ForwardRef.__forward_arg__`. + + The *owner* parameter provides the preferred mechanism for passing scope + information to this method. The owner of a :class:`~ForwardRef` is the + object that contains the annotation from which the :class:`~ForwardRef` + derives, such as a module object, type object, or function object. + + The *globals*, *locals*, and *type_params* parameters provide a more precise + mechanism for influencing the names that are available when the :class:`~ForwardRef` + is evaluated. *globals* and *locals* are passed to :func:`eval`, representing + the global and local namespaces in which the name is evaluated. + The *type_params* parameter is relevant for objects created using the native + syntax for :ref:`generic classes ` and :ref:`functions `. + It is a tuple of :ref:`type parameters ` that are in scope + while the forward reference is being evaluated. For example, if evaluating a + :class:`~ForwardRef` retrieved from an annotation found in the class namespace + of a generic class ``C``, *type_params* should be set to ``C.__type_params__``. :class:`~ForwardRef` instances returned by :func:`get_annotations` retain references to information about the scope they originated from, @@ -188,20 +211,6 @@ Classes means may not have any information about their scope, so passing arguments to this method may be necessary to evaluate them successfully. - *globals* and *locals* are passed to :func:`eval`, representing - the global and local namespaces in which the name is evaluated. - *type_params*, if given, must be a tuple of - :ref:`type parameters ` that are in scope while the forward - reference is being evaluated. *owner* is the object that owns the - annotation from which the forward reference derives, usually a function, - class, or module. - - .. important:: - - Once a :class:`~ForwardRef` instance has been evaluated, it caches - the evaluated value, and future calls to :meth:`evaluate` will return - the cached value, regardless of the parameters passed in. - .. versionadded:: 3.14 @@ -212,7 +221,7 @@ Functions Convert an annotations dict containing runtime values to a dict containing only strings. If the values are not already strings, - they are converted using :func:`value_to_string`. + they are converted using :func:`type_repr`. This is meant as a helper for user-provided annotate functions that support the :attr:`~Format.STRING` format but do not have access to the code creating the annotations. @@ -298,15 +307,13 @@ Functions .. versionadded:: 3.14 -.. function:: get_annotate_function(obj) - - Retrieve the :term:`annotate function` for *obj*. Return :const:`!None` - if *obj* does not have an annotate function. +.. function:: get_annotate_from_class_namespace(namespace) - This is usually equivalent to accessing the :attr:`~object.__annotate__` - attribute of *obj*, but direct access to the attribute may return the wrong - object in certain situations involving metaclasses. This function should be - used instead of accessing the attribute directly. + Retrieve the :term:`annotate function` from a class namespace dictionary *namespace*. + Return :const:`!None` if the namespace does not contain an annotate function. + This is primarily useful before the class has been fully created (e.g., in a metaclass); + after the class exists, the annotate function can be retrieved with ``cls.__annotate__``. + See :ref:`below ` for an example using this function in a metaclass. .. versionadded:: 3.14 @@ -315,11 +322,22 @@ Functions Compute the annotations dict for an object. *obj* may be a callable, class, module, or other object with - :attr:`~object.__annotate__` and :attr:`~object.__annotations__` attributes. - Passing in an object of any other type raises :exc:`TypeError`. + :attr:`~object.__annotate__` or :attr:`~object.__annotations__` attributes. + Passing any other object raises :exc:`TypeError`. The *format* parameter controls the format in which annotations are returned, and must be a member of the :class:`Format` enum or its integer equivalent. + The different formats work as follows: + + * VALUE: :attr:`!object.__annotations__` is tried first; if that does not exist, + the :attr:`!object.__annotate__` function is called if it exists. + * FORWARDREF: If :attr:`!object.__annotations__` exists and can be evaluated successfully, + it is used; otherwise, the :attr:`!object.__annotate__` function is called. If it + does not exist either, :attr:`!object.__annotations__` is tried again and any error + from accessing it is re-raised. + * STRING: If :attr:`!object.__annotate__` exists, it is called first; + otherwise, :attr:`!object.__annotations__` is used and stringified + using :func:`annotations_to_string`. Returns a dict. :func:`!get_annotations` returns a new dict every time it's called; calling it twice on the same object will return two @@ -380,7 +398,7 @@ Functions .. versionadded:: 3.14 -.. function:: value_to_string(value) +.. function:: type_repr(value) Convert an arbitrary Python value to a format suitable for use by the :attr:`~Format.STRING` format. This calls :func:`repr` for most @@ -394,3 +412,190 @@ Functions .. versionadded:: 3.14 + +Recipes +------- + +.. _annotationlib-metaclass: + +Using annotations in a metaclass +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A :ref:`metaclass ` may want to inspect or even modify the annotations +in a class body during class creation. Doing so requires retrieving annotations +from the class namespace dictionary. For classes created with +``from __future__ import annotations``, the annotations will be in the ``__annotations__`` +key of the dictionary. For other classes with annotations, +:func:`get_annotate_from_class_namespace` can be used to get the +annotate function, and :func:`call_annotate_function` can be used to call it and +retrieve the annotations. Using the :attr:`~Format.FORWARDREF` format will usually +be best, because this allows the annotations to refer to names that cannot yet be +resolved when the class is created. + +To modify the annotations, it is best to create a wrapper annotate function +that calls the original annotate function, makes any necessary adjustments, and +returns the result. + +Below is an example of a metaclass that filters out all :class:`typing.ClassVar` +annotations from the class and puts them in a separate attribute: + +.. code-block:: python + + import annotationlib + import typing + + class ClassVarSeparator(type): + def __new__(mcls, name, bases, ns): + if "__annotations__" in ns: # from __future__ import annotations + annotations = ns["__annotations__"] + classvar_keys = { + key for key, value in annotations.items() + # Use string comparison for simplicity; a more robust solution + # could use annotationlib.ForwardRef.evaluate + if value.startswith("ClassVar") + } + classvars = {key: annotations[key] for key in classvar_keys} + ns["__annotations__"] = { + key: value for key, value in annotations.items() + if key not in classvar_keys + } + wrapped_annotate = None + elif annotate := annotationlib.get_annotate_from_class_namespace(ns): + annotations = annotationlib.call_annotate_function( + annotate, format=annotationlib.Format.FORWARDREF + ) + classvar_keys = { + key for key, value in annotations.items() + if typing.get_origin(value) is typing.ClassVar + } + classvars = {key: annotations[key] for key in classvar_keys} + + def wrapped_annotate(format): + annos = annotationlib.call_annotate_function(annotate, format, owner=typ) + return {key: value for key, value in annos.items() if key not in classvar_keys} + + else: # no annotations + classvars = {} + wrapped_annotate = None + typ = super().__new__(mcls, name, bases, ns) + + if wrapped_annotate is not None: + # Wrap the original __annotate__ with a wrapper that removes ClassVars + typ.__annotate__ = wrapped_annotate + typ.classvars = classvars # Store the ClassVars in a separate attribute + return typ + + +Limitations of the ``STRING`` format +------------------------------------ + +The :attr:`~Format.STRING` format is meant to approximate the source code +of the annotation, but the implementation strategy used means that it is not +always possible to recover the exact source code. + +First, the stringifier of course cannot recover any information that is not present in +the compiled code, including comments, whitespace, parenthesization, and operations that +get simplified by the compiler. + +Second, the stringifier can intercept almost all operations that involve names looked +up in some scope, but it cannot intercept operations that operate fully on constants. +As a corollary, this also means it is not safe to request the ``STRING`` format on +untrusted code: Python is powerful enough that it is possible to achieve arbitrary +code execution even with no access to any globals or builtins. For example: + +.. code-block:: pycon + + >>> def f(x: (1).__class__.__base__.__subclasses__()[-1].__init__.__builtins__["print"]("Hello world")): pass + ... + >>> annotationlib.get_annotations(f, format=annotationlib.Format.SOURCE) + Hello world + {'x': 'None'} + +.. note:: + This particular example works as of the time of writing, but it relies on + implementation details and is not guaranteed to work in the future. + +Among the different kinds of expressions that exist in Python, +as represented by the :mod:`ast` module, some expressions are supported, +meaning that the ``STRING`` format can generally recover the original source code; +others are unsupported, meaning that they may result in incorrect output or an error. + +The following are supported (sometimes with caveats): + +* :class:`ast.BinOp` +* :class:`ast.UnaryOp` + + * :class:`ast.Invert` (``~``), :class:`ast.UAdd` (``+``), and :class:`ast.USub` (``-``) are supported + * :class:`ast.Not` (``not``) is not supported + +* :class:`ast.Dict` (except when using ``**`` unpacking) +* :class:`ast.Set` +* :class:`ast.Compare` + + * :class:`ast.Eq` and :class:`ast.NotEq` are supported + * :class:`ast.Lt`, :class:`ast.LtE`, :class:`ast.Gt`, and :class:`ast.GtE` are supported, but the operand may be flipped + * :class:`ast.Is`, :class:`ast.IsNot`, :class:`ast.In`, and :class:`ast.NotIn` are not supported + +* :class:`ast.Call` (except when using ``**`` unpacking) +* :class:`ast.Constant` (though not the exact representation of the constant; for example, escape + sequences in strings are lost; hexadecimal numbers are converted to decimal) +* :class:`ast.Attribute` (assuming the value is not a constant) +* :class:`ast.Subscript` (assuming the value is not a constant) +* :class:`ast.Starred` (``*`` unpacking) +* :class:`ast.Name` +* :class:`ast.List` +* :class:`ast.Tuple` +* :class:`ast.Slice` + +The following are unsupported, but throw an informative error when encountered by the +stringifier: + +* :class:`ast.FormattedValue` (f-strings; error is not detected if conversion specifiers like ``!r`` + are used) +* :class:`ast.JoinedStr` (f-strings) + +The following are unsupported and result in incorrect output: + +* :class:`ast.BoolOp` (``and`` and ``or``) +* :class:`ast.IfExp` +* :class:`ast.Lambda` +* :class:`ast.ListComp` +* :class:`ast.SetComp` +* :class:`ast.DictComp` +* :class:`ast.GeneratorExp` + +The following are disallowed in annotation scopes and therefore not relevant: + +* :class:`ast.NamedExpr` (``:=``) +* :class:`ast.Await` +* :class:`ast.Yield` +* :class:`ast.YieldFrom` + + +Limitations of the ``FORWARDREF`` format +---------------------------------------- + +The :attr:`~Format.FORWARDREF` format aims to produce real values as much +as possible, with anything that cannot be resolved replaced with +:class:`ForwardRef` objects. It is affected by broadly the same Limitations +as the :attr:`~Format.STRING` format: annotations that perform operations on +literals or that use unsupported expression types may raise exceptions when +evaluated using the :attr:`~Format.FORWARDREF` format. + +Below are a few examples of the behavior with unsupported expressions: + +.. code-block:: pycon + + >>> from annotationlib import get_annotations, Format + >>> def zerodiv(x: 1 / 0): ... + >>> get_annotations(zerodiv, format=Format.STRING) + Traceback (most recent call last): + ... + ZeroDivisionError: division by zero + >>> get_annotations(zerodiv, format=Format.FORWARDREF) + Traceback (most recent call last): + ... + ZeroDivisionError: division by zero + >>> def ifexp(x: 1 if y else 0): ... + >>> get_annotations(ifexp, format=Format.STRING) + {'x': '1'} diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 8d0116d8c060b8..29396c7a0366a1 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -74,7 +74,7 @@ ArgumentParser objects prefix_chars='-', fromfile_prefix_chars=None, \ argument_default=None, conflict_handler='error', \ add_help=True, allow_abbrev=True, exit_on_error=True, \ - suggest_on_error=False) + *, suggest_on_error=False, color=False) Create a new :class:`ArgumentParser` object. All parameters should be passed as keyword arguments. Each parameter has its own more detailed description @@ -111,7 +111,7 @@ ArgumentParser objects * add_help_ - Add a ``-h/--help`` option to the parser (default: ``True``) * allow_abbrev_ - Allows long options to be abbreviated if the - abbreviation is unambiguous. (default: ``True``) + abbreviation is unambiguous (default: ``True``) * exit_on_error_ - Determines whether or not :class:`!ArgumentParser` exits with error info when an error occurs. (default: ``True``) @@ -119,6 +119,7 @@ ArgumentParser objects * suggest_on_error_ - Enables suggestions for mistyped argument choices and subparser names (default: ``False``) + * color_ - Allow color output (default: ``False``) .. versionchanged:: 3.5 *allow_abbrev* parameter was added. @@ -130,6 +131,9 @@ ArgumentParser objects .. versionchanged:: 3.9 *exit_on_error* parameter was added. + .. versionchanged:: 3.14 + *suggest_on_error* and *color* parameters were added. + The following sections describe how each of these are used. @@ -594,7 +598,8 @@ subparser names, the feature can be enabled by setting ``suggest_on_error`` to ``True``. Note that this only applies for arguments when the choices specified are strings:: - >>> parser = argparse.ArgumentParser(description='Process some integers.', suggest_on_error=True) + >>> parser = argparse.ArgumentParser(description='Process some integers.', + suggest_on_error=True) >>> parser.add_argument('--action', choices=['sum', 'max']) >>> parser.add_argument('integers', metavar='N', type=int, nargs='+', ... help='an integer for the accumulator') @@ -612,6 +617,33 @@ keyword argument:: .. versionadded:: 3.14 +color +^^^^^ + +By default, the help message is printed in plain text. If you want to allow +color in help messages, you can enable it by setting ``color`` to ``True``:: + + >>> parser = argparse.ArgumentParser(description='Process some integers.', + ... color=True) + >>> parser.add_argument('--action', choices=['sum', 'max']) + >>> parser.add_argument('integers', metavar='N', type=int, nargs='+', + ... help='an integer for the accumulator') + >>> parser.parse_args(['--help']) + +Even if a CLI author has enabled color, it can be +:ref:`controlled using environment variables `. + +If you're writing code that needs to be compatible with older Python versions +and want to opportunistically use ``color`` when it's available, you +can set it as an attribute after initializing the parser instead of using the +keyword argument:: + + >>> parser = argparse.ArgumentParser(description='Process some integers.') + >>> parser.color = True + +.. versionadded:: 3.14 + + The add_argument() method ------------------------- diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index fd901e232855b5..ca9a6b0712c9a2 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -1,4 +1,4 @@ -:mod:`!ast` --- Abstract Syntax Trees +:mod:`!ast` --- Abstract syntax trees ===================================== .. module:: ast @@ -29,7 +29,7 @@ compiled into a Python code object using the built-in :func:`compile` function. .. _abstract-grammar: -Abstract Grammar +Abstract grammar ---------------- The abstract grammar is currently defined as follows: @@ -1190,7 +1190,7 @@ Control flow .. doctest:: - >> print(ast.dump(ast.parse(""" + >>> print(ast.dump(ast.parse(""" ... while x: ... ... ... else: @@ -1761,6 +1761,43 @@ Pattern matching .. versionadded:: 3.10 + +Type annotations +^^^^^^^^^^^^^^^^ + +.. class:: TypeIgnore(lineno, tag) + + A ``# type: ignore`` comment located at *lineno*. + *tag* is the optional tag specified by the form ``# type: ignore ``. + + .. doctest:: + + >>> print(ast.dump(ast.parse('x = 1 # type: ignore', type_comments=True), indent=4)) + Module( + body=[ + Assign( + targets=[ + Name(id='x', ctx=Store())], + value=Constant(value=1))], + type_ignores=[ + TypeIgnore(lineno=1, tag='')]) + >>> print(ast.dump(ast.parse('x: bool = 1 # type: ignore[assignment]', type_comments=True), indent=4)) + Module( + body=[ + AnnAssign( + target=Name(id='x', ctx=Store()), + annotation=Name(id='bool', ctx=Load()), + value=Constant(value=1), + simple=1)], + type_ignores=[ + TypeIgnore(lineno=1, tag='[assignment]')]) + + .. note:: + :class:`!TypeIgnore` nodes are not generated when the *type_comments* parameter + is set to ``False`` (default). See :func:`ast.parse` for more details. + + .. versionadded:: 3.8 + .. _ast-type-params: Type parameters @@ -2119,10 +2156,10 @@ Async and await of :class:`ast.operator`, :class:`ast.unaryop`, :class:`ast.cmpop`, :class:`ast.boolop` and :class:`ast.expr_context`) on the returned tree will be singletons. Changes to one will be reflected in all other - occurrences of the same value (e.g. :class:`ast.Add`). + occurrences of the same value (for example, :class:`ast.Add`). -:mod:`ast` Helpers +:mod:`ast` helpers ------------------ Apart from the node classes, the :mod:`ast` module defines these utility functions @@ -2447,7 +2484,7 @@ and classes for traversing abstract syntax trees: .. _ast-compiler-flags: -Compiler Flags +Compiler flags -------------- The following flags may be passed to :func:`compile` in order to change @@ -2496,7 +2533,7 @@ effects on the compilation of a program: .. _ast-cli: -Command-Line Usage +Command-line usage ------------------ .. versionadded:: 3.9 @@ -2535,6 +2572,28 @@ The following options are accepted: Indentation of nodes in AST (number of spaces). +.. option:: --feature-version + + Python version in the format 3.x (for example, 3.10). Defaults to the + current version of the interpreter. + + .. versionadded:: 3.14 + +.. option:: -O + --optimize + + Optimization level for parser. Defaults to no optimization. + + .. versionadded:: 3.14 + +.. option:: --show-empty + + Show empty lists and fields that are ``None``. Defaults to not showing empty + objects. + + .. versionadded:: 3.14 + + If :file:`infile` is specified its contents are parsed to AST and dumped to stdout. Otherwise, the content is read from stdin. diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst index 44b507a9811116..7831b613bd4a60 100644 --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -46,10 +46,6 @@ In addition to enabling the debug mode, consider also: When the debug mode is enabled: -* asyncio checks for :ref:`coroutines that were not awaited - ` and logs them; this mitigates - the "forgotten await" pitfall. - * Many non-threadsafe asyncio APIs (such as :meth:`loop.call_soon` and :meth:`loop.call_at` methods) raise an exception if they are called from a wrong thread. diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 15ef33e195904d..21f7d0547af1dd 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -65,18 +65,14 @@ an event loop: .. note:: The :mod:`!asyncio` policy system is deprecated and will be removed - in Python 3.16; from there on, this function will always return the - running event loop. - + in Python 3.16; from there on, this function will return the current + running event loop if present else it will return the + loop set by :func:`set_event_loop`. .. function:: set_event_loop(loop) Set *loop* as the current event loop for the current OS thread. - .. deprecated:: 3.14 - The :func:`set_event_loop` function is deprecated and will be removed - in Python 3.16. - .. function:: new_event_loop() Create and return a new event loop object. @@ -172,7 +168,8 @@ Running and stopping the loop This method is idempotent and irreversible. No other methods should be called after the event loop is closed. -.. coroutinemethod:: loop.shutdown_asyncgens() +.. method:: loop.shutdown_asyncgens() + :async: Schedule all currently open :term:`asynchronous generator` objects to close with an :meth:`~agen.aclose` call. After calling this method, @@ -193,7 +190,8 @@ Running and stopping the loop .. versionadded:: 3.6 -.. coroutinemethod:: loop.shutdown_default_executor(timeout=None) +.. method:: loop.shutdown_default_executor(timeout=None) + :async: Schedule the closure of the default executor and wait for it to join all of the threads in the :class:`~concurrent.futures.ThreadPoolExecutor`. @@ -363,7 +361,7 @@ Creating Futures and Tasks .. versionadded:: 3.5.2 -.. method:: loop.create_task(coro, *, name=None, context=None) +.. method:: loop.create_task(coro, *, name=None, context=None, eager_start=None) Schedule the execution of :ref:`coroutine ` *coro*. Return a :class:`Task` object. @@ -379,12 +377,20 @@ Creating Futures and Tasks custom :class:`contextvars.Context` for the *coro* to run in. The current context copy is created when no *context* is provided. + An optional keyword-only *eager_start* argument allows specifying + if the task should execute eagerly during the call to create_task, + or be scheduled later. If *eager_start* is not passed the mode set + by :meth:`loop.set_task_factory` will be used. + .. versionchanged:: 3.8 Added the *name* parameter. .. versionchanged:: 3.11 Added the *context* parameter. + .. versionchanged:: 3.14 + Added the *eager_start* parameter. + .. method:: loop.set_task_factory(factory) Set a task factory that will be used by @@ -404,14 +410,15 @@ Creating Futures and Tasks Opening network connections ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. coroutinemethod:: loop.create_connection(protocol_factory, \ - host=None, port=None, *, ssl=None, \ - family=0, proto=0, flags=0, sock=None, \ - local_addr=None, server_hostname=None, \ - ssl_handshake_timeout=None, \ - ssl_shutdown_timeout=None, \ - happy_eyeballs_delay=None, interleave=None, \ - all_errors=False) +.. method:: loop.create_connection(protocol_factory, \ + host=None, port=None, *, ssl=None, \ + family=0, proto=0, flags=0, sock=None, \ + local_addr=None, server_hostname=None, \ + ssl_handshake_timeout=None, \ + ssl_shutdown_timeout=None, \ + happy_eyeballs_delay=None, interleave=None, \ + all_errors=False) + :async: Open a streaming transport connection to a given address specified by *host* and *port*. @@ -557,11 +564,12 @@ Opening network connections API. It returns a pair of (:class:`StreamReader`, :class:`StreamWriter`) that can be used directly in async/await code. -.. coroutinemethod:: loop.create_datagram_endpoint(protocol_factory, \ - local_addr=None, remote_addr=None, *, \ - family=0, proto=0, flags=0, \ - reuse_port=None, \ - allow_broadcast=None, sock=None) +.. method:: loop.create_datagram_endpoint(protocol_factory, \ + local_addr=None, remote_addr=None, *, \ + family=0, proto=0, flags=0, \ + reuse_port=None, \ + allow_broadcast=None, sock=None) + :async: Create a datagram connection. @@ -642,10 +650,11 @@ Opening network connections The *reuse_address* parameter, disabled since Python 3.8.1, 3.7.6 and 3.6.10, has been entirely removed. -.. coroutinemethod:: loop.create_unix_connection(protocol_factory, \ - path=None, *, ssl=None, sock=None, \ - server_hostname=None, ssl_handshake_timeout=None, \ - ssl_shutdown_timeout=None) +.. method:: loop.create_unix_connection(protocol_factory, \ + path=None, *, ssl=None, sock=None, \ + server_hostname=None, ssl_handshake_timeout=None, \ + ssl_shutdown_timeout=None) + :async: Create a Unix connection. @@ -678,16 +687,17 @@ Creating network servers .. _loop_create_server: -.. coroutinemethod:: loop.create_server(protocol_factory, \ - host=None, port=None, *, \ - family=socket.AF_UNSPEC, \ - flags=socket.AI_PASSIVE, \ - sock=None, backlog=100, ssl=None, \ - reuse_address=None, reuse_port=None, \ - keep_alive=None, \ - ssl_handshake_timeout=None, \ - ssl_shutdown_timeout=None, \ - start_serving=True) +.. method:: loop.create_server(protocol_factory, \ + host=None, port=None, *, \ + family=socket.AF_UNSPEC, \ + flags=socket.AI_PASSIVE, \ + sock=None, backlog=100, ssl=None, \ + reuse_address=None, reuse_port=None, \ + keep_alive=None, \ + ssl_handshake_timeout=None, \ + ssl_shutdown_timeout=None, \ + start_serving=True) + :async: Create a TCP server (socket type :const:`~socket.SOCK_STREAM`) listening on *port* of the *host* address. @@ -795,11 +805,12 @@ Creating network servers that can be used in an async/await code. -.. coroutinemethod:: loop.create_unix_server(protocol_factory, path=None, \ - *, sock=None, backlog=100, ssl=None, \ - ssl_handshake_timeout=None, \ - ssl_shutdown_timeout=None, \ - start_serving=True, cleanup_socket=True) +.. method:: loop.create_unix_server(protocol_factory, path=None, \ + *, sock=None, backlog=100, ssl=None, \ + ssl_handshake_timeout=None, \ + ssl_shutdown_timeout=None, \ + start_serving=True, cleanup_socket=True) + :async: Similar to :meth:`loop.create_server` but works with the :py:const:`~socket.AF_UNIX` socket family. @@ -832,9 +843,10 @@ Creating network servers Added the *cleanup_socket* parameter. -.. coroutinemethod:: loop.connect_accepted_socket(protocol_factory, \ - sock, *, ssl=None, ssl_handshake_timeout=None, \ - ssl_shutdown_timeout=None) +.. method:: loop.connect_accepted_socket(protocol_factory, \ + sock, *, ssl=None, ssl_handshake_timeout=None, \ + ssl_shutdown_timeout=None) + :async: Wrap an already accepted connection into a transport/protocol pair. @@ -882,8 +894,9 @@ Creating network servers Transferring files ^^^^^^^^^^^^^^^^^^ -.. coroutinemethod:: loop.sendfile(transport, file, \ - offset=0, count=None, *, fallback=True) +.. method:: loop.sendfile(transport, file, \ + offset=0, count=None, *, fallback=True) + :async: Send a *file* over a *transport*. Return the total number of bytes sent. @@ -912,10 +925,11 @@ Transferring files TLS Upgrade ^^^^^^^^^^^ -.. coroutinemethod:: loop.start_tls(transport, protocol, \ - sslcontext, *, server_side=False, \ - server_hostname=None, ssl_handshake_timeout=None, \ - ssl_shutdown_timeout=None) +.. method:: loop.start_tls(transport, protocol, \ + sslcontext, *, server_side=False, \ + server_hostname=None, ssl_handshake_timeout=None, \ + ssl_shutdown_timeout=None) + :async: Upgrade an existing transport-based connection to TLS. @@ -1009,7 +1023,8 @@ However, there are some use cases when performance is not critical, and working with :class:`~socket.socket` objects directly is more convenient. -.. coroutinemethod:: loop.sock_recv(sock, nbytes) +.. method:: loop.sock_recv(sock, nbytes) + :async: Receive up to *nbytes* from *sock*. Asynchronous version of :meth:`socket.recv() `. @@ -1023,7 +1038,8 @@ convenient. method, releases before Python 3.7 returned a :class:`Future`. Since Python 3.7 this is an ``async def`` method. -.. coroutinemethod:: loop.sock_recv_into(sock, buf) +.. method:: loop.sock_recv_into(sock, buf) + :async: Receive data from *sock* into the *buf* buffer. Modeled after the blocking :meth:`socket.recv_into() ` method. @@ -1034,7 +1050,8 @@ convenient. .. versionadded:: 3.7 -.. coroutinemethod:: loop.sock_recvfrom(sock, bufsize) +.. method:: loop.sock_recvfrom(sock, bufsize) + :async: Receive a datagram of up to *bufsize* from *sock*. Asynchronous version of :meth:`socket.recvfrom() `. @@ -1045,7 +1062,8 @@ convenient. .. versionadded:: 3.11 -.. coroutinemethod:: loop.sock_recvfrom_into(sock, buf, nbytes=0) +.. method:: loop.sock_recvfrom_into(sock, buf, nbytes=0) + :async: Receive a datagram of up to *nbytes* from *sock* into *buf*. Asynchronous version of @@ -1057,7 +1075,8 @@ convenient. .. versionadded:: 3.11 -.. coroutinemethod:: loop.sock_sendall(sock, data) +.. method:: loop.sock_sendall(sock, data) + :async: Send *data* to the *sock* socket. Asynchronous version of :meth:`socket.sendall() `. @@ -1075,7 +1094,8 @@ convenient. method, before Python 3.7 it returned a :class:`Future`. Since Python 3.7, this is an ``async def`` method. -.. coroutinemethod:: loop.sock_sendto(sock, data, address) +.. method:: loop.sock_sendto(sock, data, address) + :async: Send a datagram from *sock* to *address*. Asynchronous version of @@ -1087,7 +1107,8 @@ convenient. .. versionadded:: 3.11 -.. coroutinemethod:: loop.sock_connect(sock, address) +.. method:: loop.sock_connect(sock, address) + :async: Connect *sock* to a remote socket at *address*. @@ -1108,7 +1129,8 @@ convenient. and :func:`asyncio.open_connection() `. -.. coroutinemethod:: loop.sock_accept(sock) +.. method:: loop.sock_accept(sock) + :async: Accept a connection. Modeled after the blocking :meth:`socket.accept() ` method. @@ -1130,8 +1152,9 @@ convenient. :meth:`loop.create_server` and :func:`start_server`. -.. coroutinemethod:: loop.sock_sendfile(sock, file, offset=0, count=None, \ - *, fallback=True) +.. method:: loop.sock_sendfile(sock, file, offset=0, count=None, \ + *, fallback=True) + :async: Send a file using high-performance :mod:`os.sendfile` if possible. Return the total number of bytes sent. @@ -1165,12 +1188,14 @@ convenient. DNS ^^^ -.. coroutinemethod:: loop.getaddrinfo(host, port, *, family=0, \ - type=0, proto=0, flags=0) +.. method:: loop.getaddrinfo(host, port, *, family=0, \ + type=0, proto=0, flags=0) + :async: Asynchronous version of :meth:`socket.getaddrinfo`. -.. coroutinemethod:: loop.getnameinfo(sockaddr, flags=0) +.. method:: loop.getnameinfo(sockaddr, flags=0) + :async: Asynchronous version of :meth:`socket.getnameinfo`. @@ -1192,7 +1217,8 @@ DNS Working with pipes ^^^^^^^^^^^^^^^^^^ -.. coroutinemethod:: loop.connect_read_pipe(protocol_factory, pipe) +.. method:: loop.connect_read_pipe(protocol_factory, pipe) + :async: Register the read end of *pipe* in the event loop. @@ -1208,7 +1234,8 @@ Working with pipes With :class:`SelectorEventLoop` event loop, the *pipe* is set to non-blocking mode. -.. coroutinemethod:: loop.connect_write_pipe(protocol_factory, pipe) +.. method:: loop.connect_write_pipe(protocol_factory, pipe) + :async: Register the write end of *pipe* in the event loop. @@ -1421,6 +1448,8 @@ Allows customizing how exceptions are handled in the event loop. * 'protocol' (optional): :ref:`Protocol ` instance; * 'transport' (optional): :ref:`Transport ` instance; * 'socket' (optional): :class:`socket.socket` instance; + * 'source_traceback' (optional): Traceback of the source; + * 'handle_traceback' (optional): Traceback of the handle; * 'asyncgen' (optional): Asynchronous generator that caused the exception. @@ -1480,9 +1509,10 @@ async/await code consider using the high-level .. _loop_subprocess_exec: -.. coroutinemethod:: loop.subprocess_exec(protocol_factory, *args, \ - stdin=subprocess.PIPE, stdout=subprocess.PIPE, \ - stderr=subprocess.PIPE, **kwargs) +.. method:: loop.subprocess_exec(protocol_factory, *args, \ + stdin=subprocess.PIPE, stdout=subprocess.PIPE, \ + stderr=subprocess.PIPE, **kwargs) + :async: Create a subprocess from one or more string arguments specified by *args*. @@ -1562,9 +1592,10 @@ async/await code consider using the high-level conforms to the :class:`asyncio.SubprocessTransport` base class and *protocol* is an object instantiated by the *protocol_factory*. -.. coroutinemethod:: loop.subprocess_shell(protocol_factory, cmd, *, \ - stdin=subprocess.PIPE, stdout=subprocess.PIPE, \ - stderr=subprocess.PIPE, **kwargs) +.. method:: loop.subprocess_shell(protocol_factory, cmd, *, \ + stdin=subprocess.PIPE, stdout=subprocess.PIPE, \ + stderr=subprocess.PIPE, **kwargs) + :async: Create a subprocess from *cmd*, which can be a :class:`str` or a :class:`bytes` string encoded to the @@ -1709,7 +1740,8 @@ Do not instantiate the :class:`Server` class directly. .. versionadded:: 3.7 - .. coroutinemethod:: start_serving() + .. method:: start_serving() + :async: Start accepting connections. @@ -1725,7 +1757,8 @@ Do not instantiate the :class:`Server` class directly. .. versionadded:: 3.7 - .. coroutinemethod:: serve_forever() + .. method:: serve_forever() + :async: Start accepting connections until the coroutine is cancelled. Cancellation of ``serve_forever`` task causes the server @@ -1757,7 +1790,8 @@ Do not instantiate the :class:`Server` class directly. .. versionadded:: 3.7 - .. coroutinemethod:: wait_closed() + .. method:: wait_closed() + :async: Wait until the :meth:`close` method completes and all active connections have finished. diff --git a/Doc/library/asyncio-future.rst b/Doc/library/asyncio-future.rst index 9dce0731411940..32771ba72e0002 100644 --- a/Doc/library/asyncio-future.rst +++ b/Doc/library/asyncio-future.rst @@ -51,12 +51,13 @@ Future Functions .. important:: - See also the :func:`create_task` function which is the - preferred way for creating new Tasks. - Save a reference to the result of this function, to avoid a task disappearing mid-execution. + See also the :func:`create_task` function which is the + preferred way for creating new tasks or use :class:`asyncio.TaskGroup` + which keeps reference to the task internally. + .. versionchanged:: 3.5.1 The function accepts any :term:`awaitable` object. diff --git a/Doc/library/asyncio-queue.rst b/Doc/library/asyncio-queue.rst index 066edd424d150e..d99213aa81d53e 100644 --- a/Doc/library/asyncio-queue.rst +++ b/Doc/library/asyncio-queue.rst @@ -57,7 +57,8 @@ Queue If the queue was initialized with ``maxsize=0`` (the default), then :meth:`full` never returns ``True``. - .. coroutinemethod:: get() + .. method:: get() + :async: Remove and return an item from the queue. If queue is empty, wait until an item is available. @@ -70,7 +71,8 @@ Queue Return an item if one is immediately available, else raise :exc:`QueueEmpty`. - .. coroutinemethod:: join() + .. method:: join() + :async: Block until all items in the queue have been received and processed. @@ -80,7 +82,8 @@ Queue work on it is complete. When the count of unfinished tasks drops to zero, :meth:`join` unblocks. - .. coroutinemethod:: put(item) + .. method:: put(item) + :async: Put an item into the queue. If the queue is full, wait until a free slot is available before adding the item. diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index 48f2890c5eef8c..c56166cabb9093 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -48,12 +48,13 @@ The following top-level asyncio functions can be used to create and work with streams: -.. coroutinefunction:: open_connection(host=None, port=None, *, \ - limit=None, ssl=None, family=0, proto=0, \ - flags=0, sock=None, local_addr=None, \ - server_hostname=None, ssl_handshake_timeout=None, \ - ssl_shutdown_timeout=None, \ - happy_eyeballs_delay=None, interleave=None) +.. function:: open_connection(host=None, port=None, *, \ + limit=None, ssl=None, family=0, proto=0, \ + flags=0, sock=None, local_addr=None, \ + server_hostname=None, ssl_handshake_timeout=None, \ + ssl_shutdown_timeout=None, \ + happy_eyeballs_delay=None, interleave=None) + :async: Establish a network connection and return a pair of ``(reader, writer)`` objects. @@ -87,14 +88,15 @@ and work with streams: Added the *ssl_shutdown_timeout* parameter. -.. coroutinefunction:: start_server(client_connected_cb, host=None, \ - port=None, *, limit=None, \ - family=socket.AF_UNSPEC, \ - flags=socket.AI_PASSIVE, sock=None, \ - backlog=100, ssl=None, reuse_address=None, \ - reuse_port=None, keep_alive=None, \ - ssl_handshake_timeout=None, \ - ssl_shutdown_timeout=None, start_serving=True) +.. function:: start_server(client_connected_cb, host=None, \ + port=None, *, limit=None, \ + family=socket.AF_UNSPEC, \ + flags=socket.AI_PASSIVE, sock=None, \ + backlog=100, ssl=None, reuse_address=None, \ + reuse_port=None, keep_alive=None, \ + ssl_handshake_timeout=None, \ + ssl_shutdown_timeout=None, start_serving=True) + :async: Start a socket server. @@ -135,9 +137,10 @@ and work with streams: .. rubric:: Unix Sockets -.. coroutinefunction:: open_unix_connection(path=None, *, limit=None, \ - ssl=None, sock=None, server_hostname=None, \ - ssl_handshake_timeout=None, ssl_shutdown_timeout=None) +.. function:: open_unix_connection(path=None, *, limit=None, \ + ssl=None, sock=None, server_hostname=None, \ + ssl_handshake_timeout=None, ssl_shutdown_timeout=None) + :async: Establish a Unix socket connection and return a pair of ``(reader, writer)``. @@ -165,10 +168,11 @@ and work with streams: Added the *ssl_shutdown_timeout* parameter. -.. coroutinefunction:: start_unix_server(client_connected_cb, path=None, \ - *, limit=None, sock=None, backlog=100, ssl=None, \ - ssl_handshake_timeout=None, \ - ssl_shutdown_timeout=None, start_serving=True) +.. function:: start_unix_server(client_connected_cb, path=None, \ + *, limit=None, sock=None, backlog=100, ssl=None, \ + ssl_handshake_timeout=None, \ + ssl_shutdown_timeout=None, start_serving=True) + :async: Start a Unix socket server. @@ -212,7 +216,8 @@ StreamReader Acknowledge the EOF. - .. coroutinemethod:: read(n=-1) + .. method:: read(n=-1) + :async: Read up to *n* bytes from the stream. @@ -228,7 +233,8 @@ StreamReader If EOF is received before any byte is read, return an empty ``bytes`` object. - .. coroutinemethod:: readline() + .. method:: readline() + :async: Read one line, where "line" is a sequence of bytes ending with ``\n``. @@ -239,7 +245,8 @@ StreamReader If EOF is received and the internal buffer is empty, return an empty ``bytes`` object. - .. coroutinemethod:: readexactly(n) + .. method:: readexactly(n) + :async: Read exactly *n* bytes. @@ -247,7 +254,8 @@ StreamReader can be read. Use the :attr:`IncompleteReadError.partial` attribute to get the partially read data. - .. coroutinemethod:: readuntil(separator=b'\n') + .. method:: readuntil(separator=b'\n') + :async: Read data from the stream until *separator* is found. @@ -347,7 +355,8 @@ StreamWriter Access optional transport information; see :meth:`BaseTransport.get_extra_info` for details. - .. coroutinemethod:: drain() + .. method:: drain() + :async: Wait until it is appropriate to resume writing to the stream. Example:: @@ -362,8 +371,9 @@ StreamWriter be resumed. When there is nothing to wait for, the :meth:`drain` returns immediately. - .. coroutinemethod:: start_tls(sslcontext, *, server_hostname=None, \ - ssl_handshake_timeout=None, ssl_shutdown_timeout=None) + .. method:: start_tls(sslcontext, *, server_hostname=None, \ + ssl_handshake_timeout=None, ssl_shutdown_timeout=None) + :async: Upgrade an existing stream-based connection to TLS. @@ -395,7 +405,8 @@ StreamWriter .. versionadded:: 3.7 - .. coroutinemethod:: wait_closed() + .. method:: wait_closed() + :async: Wait until the stream is closed. diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst index b477a7fa2d37ef..03e76bc868905e 100644 --- a/Doc/library/asyncio-subprocess.rst +++ b/Doc/library/asyncio-subprocess.rst @@ -61,13 +61,14 @@ See also the `Examples`_ subsection. Creating Subprocesses ===================== -.. coroutinefunction:: create_subprocess_exec(program, *args, stdin=None, \ - stdout=None, stderr=None, limit=None, **kwds) +.. function:: create_subprocess_exec(program, *args, stdin=None, \ + stdout=None, stderr=None, limit=None, **kwds) + :async: Create a subprocess. The *limit* argument sets the buffer limit for :class:`StreamReader` - wrappers for :attr:`Process.stdout` and :attr:`Process.stderr` + wrappers for :attr:`~asyncio.subprocess.Process.stdout` and :attr:`~asyncio.subprocess.Process.stderr` (if :const:`subprocess.PIPE` is passed to *stdout* and *stderr* arguments). Return a :class:`~asyncio.subprocess.Process` instance. @@ -79,13 +80,14 @@ Creating Subprocesses Removed the *loop* parameter. -.. coroutinefunction:: create_subprocess_shell(cmd, stdin=None, \ - stdout=None, stderr=None, limit=None, **kwds) +.. function:: create_subprocess_shell(cmd, stdin=None, \ + stdout=None, stderr=None, limit=None, **kwds) + :async: Run the *cmd* shell command. The *limit* argument sets the buffer limit for :class:`StreamReader` - wrappers for :attr:`Process.stdout` and :attr:`Process.stderr` + wrappers for :attr:`~asyncio.subprocess.Process.stdout` and :attr:`~asyncio.subprocess.Process.stderr` (if :const:`subprocess.PIPE` is passed to *stdout* and *stderr* arguments). Return a :class:`~asyncio.subprocess.Process` instance. @@ -130,12 +132,12 @@ Constants If *PIPE* is passed to *stdin* argument, the :attr:`Process.stdin ` attribute - will point to a :class:`StreamWriter` instance. + will point to a :class:`~asyncio.StreamWriter` instance. If *PIPE* is passed to *stdout* or *stderr* arguments, the :attr:`Process.stdout ` and :attr:`Process.stderr ` - attributes will point to :class:`StreamReader` instances. + attributes will point to :class:`~asyncio.StreamReader` instances. .. data:: asyncio.subprocess.STDOUT :module: @@ -163,7 +165,7 @@ their completion. :module: An object that wraps OS processes created by the - :func:`create_subprocess_exec` and :func:`create_subprocess_shell` + :func:`~asyncio.create_subprocess_exec` and :func:`~asyncio.create_subprocess_shell` functions. This class is designed to have a similar API to the @@ -188,7 +190,8 @@ their completion. See also the :ref:`Subprocess and Threads ` section. - .. coroutinemethod:: wait() + .. method:: wait() + :async: Wait for the child process to terminate. @@ -202,7 +205,8 @@ their completion. more data. Use the :meth:`communicate` method when using pipes to avoid this condition. - .. coroutinemethod:: communicate(input=None) + .. method:: communicate(input=None) + :async: Interact with process: @@ -232,7 +236,7 @@ their completion. .. versionchanged:: 3.12 - *stdin* gets closed when `input=None` too. + *stdin* gets closed when ``input=None`` too. .. method:: send_signal(signal) @@ -259,24 +263,24 @@ their completion. Kill the child process. - On POSIX systems this method sends :py:data:`SIGKILL` to the child + On POSIX systems this method sends :py:data:`~signal.SIGKILL` to the child process. On Windows this method is an alias for :meth:`terminate`. .. attribute:: stdin - Standard input stream (:class:`StreamWriter`) or ``None`` + Standard input stream (:class:`~asyncio.StreamWriter`) or ``None`` if the process was created with ``stdin=None``. .. attribute:: stdout - Standard output stream (:class:`StreamReader`) or ``None`` + Standard output stream (:class:`~asyncio.StreamReader`) or ``None`` if the process was created with ``stdout=None``. .. attribute:: stderr - Standard error stream (:class:`StreamReader`) or ``None`` + Standard error stream (:class:`~asyncio.StreamReader`) or ``None`` if the process was created with ``stderr=None``. .. warning:: @@ -292,7 +296,7 @@ their completion. Process identification number (PID). - Note that for processes created by the :func:`create_subprocess_shell` + Note that for processes created by the :func:`~asyncio.create_subprocess_shell` function, this attribute is the PID of the spawned shell. .. attribute:: returncode diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst index 77c2e97da11990..968c812ee3c8e6 100644 --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -67,7 +67,8 @@ Lock .. versionchanged:: 3.10 Removed the *loop* parameter. - .. coroutinemethod:: acquire() + .. method:: acquire() + :async: Acquire the lock. @@ -137,7 +138,8 @@ Event asyncio.run(main()) - .. coroutinemethod:: wait() + .. method:: wait() + :async: Wait until the event is set. @@ -207,7 +209,8 @@ Condition finally: cond.release() - .. coroutinemethod:: acquire() + .. method:: acquire() + :async: Acquire the underlying lock. @@ -245,7 +248,8 @@ Condition When invoked on an unlocked lock, a :exc:`RuntimeError` is raised. - .. coroutinemethod:: wait() + .. method:: wait() + :async: Wait until notified. @@ -262,7 +266,8 @@ Condition and be prepared to :meth:`~Condition.wait` again. For this reason, you may prefer to use :meth:`~Condition.wait_for` instead. - .. coroutinemethod:: wait_for(predicate) + .. method:: wait_for(predicate) + :async: Wait until a predicate becomes *true*. @@ -312,7 +317,8 @@ Semaphore finally: sem.release() - .. coroutinemethod:: acquire() + .. method:: acquire() + :async: Acquire a semaphore. @@ -400,7 +406,8 @@ Barrier .. versionadded:: 3.11 - .. coroutinemethod:: wait() + .. method:: wait() + :async: Pass the barrier. When all the tasks party to the barrier have called this function, they are all unblocked simultaneously. @@ -424,14 +431,16 @@ Barrier barrier is broken or reset while a task is waiting. It could raise a :exc:`CancelledError` if a task is cancelled. - .. coroutinemethod:: reset() + .. method:: reset() + :async: Return the barrier to the default, empty state. Any tasks waiting on it will receive the :class:`BrokenBarrierError` exception. If a barrier is broken it may be better to just leave it and create a new one. - .. coroutinemethod:: abort() + .. method:: abort() + :async: Put the barrier into a broken state. This causes any active or future calls to :meth:`~Barrier.wait` to fail with the :class:`BrokenBarrierError`. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 4541cf28de0605..59acce1990ae04 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -464,7 +464,8 @@ Expected output: Sleeping ======== -.. coroutinefunction:: sleep(delay, result=None) +.. function:: sleep(delay, result=None) + :async: Block for *delay* seconds. @@ -819,7 +820,8 @@ Timeouts .. versionadded:: 3.11 -.. coroutinefunction:: wait_for(aw, timeout) +.. function:: wait_for(aw, timeout) + :async: Wait for the *aw* :ref:`awaitable ` to complete with a timeout. @@ -879,7 +881,8 @@ Timeouts Waiting Primitives ================== -.. coroutinefunction:: wait(aws, *, timeout=None, return_when=ALL_COMPLETED) +.. function:: wait(aws, *, timeout=None, return_when=ALL_COMPLETED) + :async: Run :class:`~asyncio.Future` and :class:`~asyncio.Task` instances in the *aws* iterable concurrently and block until the condition specified @@ -998,7 +1001,8 @@ Waiting Primitives Running in Threads ================== -.. coroutinefunction:: to_thread(func, /, *args, **kwargs) +.. function:: to_thread(func, /, *args, **kwargs) + :async: Asynchronously run function *func* in a separate thread. @@ -1377,7 +1381,10 @@ Task Object Request the Task to be cancelled. - This arranges for a :exc:`CancelledError` exception to be thrown + If the Task is already *done* or *cancelled*, return ``False``, + otherwise, return ``True``. + + The method arranges for a :exc:`CancelledError` exception to be thrown into the wrapped coroutine on the next cycle of the event loop. The coroutine then has a chance to clean up or even deny the diff --git a/Doc/library/audit_events.rst b/Doc/library/audit_events.rst index a2a90a00d0cfca..73a58092024631 100644 --- a/Doc/library/audit_events.rst +++ b/Doc/library/audit_events.rst @@ -23,25 +23,30 @@ information on handling these events. The following events are raised internally and do not correspond to any public API of CPython: -+--------------------------+-------------------------------------------+ -| Audit event | Arguments | -+==========================+===========================================+ -| _winapi.CreateFile | ``file_name``, ``desired_access``, | -| | ``share_mode``, ``creation_disposition``, | -| | ``flags_and_attributes`` | -+--------------------------+-------------------------------------------+ -| _winapi.CreateJunction | ``src_path``, ``dst_path`` | -+--------------------------+-------------------------------------------+ -| _winapi.CreateNamedPipe | ``name``, ``open_mode``, ``pipe_mode`` | -+--------------------------+-------------------------------------------+ -| _winapi.CreatePipe | | -+--------------------------+-------------------------------------------+ -| _winapi.CreateProcess | ``application_name``, ``command_line``, | -| | ``current_directory`` | -+--------------------------+-------------------------------------------+ -| _winapi.OpenProcess | ``process_id``, ``desired_access`` | -+--------------------------+-------------------------------------------+ -| _winapi.TerminateProcess | ``handle``, ``exit_code`` | -+--------------------------+-------------------------------------------+ -| ctypes.PyObj_FromPtr | ``obj`` | -+--------------------------+-------------------------------------------+ ++----------------------------+-------------------------------------------+ +| Audit event | Arguments | ++============================+===========================================+ +| _winapi.CreateFile | ``file_name``, ``desired_access``, | +| | ``share_mode``, ``creation_disposition``, | +| | ``flags_and_attributes`` | ++----------------------------+-------------------------------------------+ +| _winapi.CreateJunction | ``src_path``, ``dst_path`` | ++----------------------------+-------------------------------------------+ +| _winapi.CreateNamedPipe | ``name``, ``open_mode``, ``pipe_mode`` | ++----------------------------+-------------------------------------------+ +| _winapi.CreatePipe | | ++----------------------------+-------------------------------------------+ +| _winapi.CreateProcess | ``application_name``, ``command_line``, | +| | ``current_directory`` | ++----------------------------+-------------------------------------------+ +| _winapi.OpenProcess | ``process_id``, ``desired_access`` | ++----------------------------+-------------------------------------------+ +| _winapi.TerminateProcess | ``handle``, ``exit_code`` | ++----------------------------+-------------------------------------------+ +| _posixsubprocess.fork_exec | ``exec_list``, ``args``, ``env`` | ++----------------------------+-------------------------------------------+ +| ctypes.PyObj_FromPtr | ``obj`` | ++----------------------------+-------------------------------------------+ + +.. versionadded:: 3.14 + The ``_posixsubprocess.fork_exec`` internal audit event. diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst index 834ab2536e6c14..529a7242443820 100644 --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -15,14 +15,9 @@ This module provides functions for encoding binary data to printable ASCII characters and decoding such encodings back to binary data. -It provides encoding and decoding functions for the encodings specified in -:rfc:`4648`, which defines the Base16, Base32, and Base64 algorithms, -and for the de-facto standard Ascii85 and Base85 encodings. - -The :rfc:`4648` encodings are suitable for encoding binary data so that it can be -safely sent by email, used as parts of URLs, or included as part of an HTTP -POST request. The encoding algorithm is not the same as the -:program:`uuencode` program. +This includes the :ref:`encodings specified in ` +:rfc:`4648` (Base64, Base32 and Base16) +and the non-standard :ref:`Base85 encodings `. There are two interfaces provided by this module. The modern interface supports encoding :term:`bytes-like objects ` to ASCII @@ -30,7 +25,7 @@ supports encoding :term:`bytes-like objects ` to ASCII strings containing ASCII to :class:`bytes`. Both base-64 alphabets defined in :rfc:`4648` (normal, and URL- and filesystem-safe) are supported. -The legacy interface does not support decoding from strings, but it does +The :ref:`legacy interface ` does not support decoding from strings, but it does provide functions for encoding and decoding to and from :term:`file objects `. It only supports the Base64 standard alphabet, and it adds newlines every 76 characters as per :rfc:`2045`. Note that if you are looking @@ -46,7 +41,15 @@ package instead. Any :term:`bytes-like objects ` are now accepted by all encoding and decoding functions in this module. Ascii85/Base85 support added. -The modern interface provides: + +.. _base64-rfc-4648: + +RFC 4648 Encodings +------------------ + +The :rfc:`4648` encodings are suitable for encoding binary data so that it can be +safely sent by email, used as parts of URLs, or included as part of an HTTP +POST request. .. function:: b64encode(s, altchars=None) @@ -181,6 +184,26 @@ The modern interface provides: incorrectly padded or if there are non-alphabet characters present in the input. +.. _base64-base-85: + +Base85 Encodings +----------------- + +Base85 encoding is not formally specified but rather a de facto standard, +thus different systems perform the encoding differently. + +The :func:`a85encode` and :func:`b85encode` functions in this module are two implementations of +the de facto standard. You should call the function with the Base85 +implementation used by the software you intend to work with. + +The two functions present in this module differ in how they handle the following: + +* Whether to include enclosing ``<~`` and ``~>`` markers +* Whether to include newline characters +* The set of ASCII characters used for encoding +* Handling of null bytes + +Refer to the documentation of the individual functions for more information. .. function:: a85encode(b, *, foldspaces=False, wrapcol=0, pad=False, adobe=False) @@ -262,7 +285,10 @@ The modern interface provides: .. versionadded:: 3.13 -The legacy interface: +.. _base64-legacy: + +Legacy Interface +---------------- .. function:: decode(input, output) diff --git a/Doc/library/bdb.rst b/Doc/library/bdb.rst index 85df7914a9a014..90f042aa377711 100644 --- a/Doc/library/bdb.rst +++ b/Doc/library/bdb.rst @@ -118,7 +118,7 @@ The :mod:`bdb` module also defines two classes: Count of the number of times a :class:`Breakpoint` has been hit. -.. class:: Bdb(skip=None) +.. class:: Bdb(skip=None, backend='settrace') The :class:`Bdb` class acts as a generic Python debugger base class. @@ -132,9 +132,22 @@ The :mod:`bdb` module also defines two classes: frame is considered to originate in a certain module is determined by the ``__name__`` in the frame globals. + The *backend* argument specifies the backend to use for :class:`Bdb`. It + can be either ``'settrace'`` or ``'monitoring'``. ``'settrace'`` uses + :func:`sys.settrace` which has the best backward compatibility. The + ``'monitoring'`` backend uses the new :mod:`sys.monitoring` that was + introduced in Python 3.12, which can be much more efficient because it + can disable unused events. We are trying to keep the exact interfaces + for both backends, but there are some differences. The debugger developers + are encouraged to use the ``'monitoring'`` backend to achieve better + performance. + .. versionchanged:: 3.1 Added the *skip* parameter. + .. versionchanged:: 3.14 + Added the *backend* parameter. + The following methods of :class:`Bdb` normally don't need to be overridden. .. method:: canonic(filename) @@ -146,6 +159,20 @@ The :mod:`bdb` module also defines two classes: `. A *filename* with angle brackets, such as ``""`` generated in interactive mode, is returned unchanged. + .. method:: start_trace(self) + + Start tracing. For ``'settrace'`` backend, this method is equivalent to + ``sys.settrace(self.trace_dispatch)`` + + .. versionadded:: 3.14 + + .. method:: stop_trace(self) + + Stop tracing. For ``'settrace'`` backend, this method is equivalent to + ``sys.settrace(None)`` + + .. versionadded:: 3.14 + .. method:: reset() Set the :attr:`!botframe`, :attr:`!stopframe`, :attr:`!returnframe` and @@ -364,6 +391,28 @@ The :mod:`bdb` module also defines two classes: Return all breakpoints that are set. + Derived classes and clients can call the following methods to disable and + restart events to achieve better performance. These methods only work + when using the ``'monitoring'`` backend. + + .. method:: disable_current_event() + + Disable the current event until the next time :func:`restart_events` is + called. This is helpful when the debugger is not interested in the current + line. + + .. versionadded:: 3.14 + + .. method:: restart_events() + + Restart all the disabled events. This function is automatically called in + ``dispatch_*`` methods after ``user_*`` methods are called. If the + ``dispatch_*`` methods are not overridden, the disabled events will be + restarted after each user interaction. + + .. versionadded:: 3.14 + + Derived classes and clients can call the following methods to get a data structure representing a stack trace. diff --git a/Doc/library/cmath.rst b/Doc/library/cmath.rst index e7c027dd4d0c22..26518a0458fd81 100644 --- a/Doc/library/cmath.rst +++ b/Doc/library/cmath.rst @@ -38,6 +38,57 @@ the function is then applied to the result of the conversion. 1.4142135623730951j +==================================================== ============================================ +**Conversions to and from polar coordinates** +-------------------------------------------------------------------------------------------------- +:func:`phase(z) ` Return the phase of *z* +:func:`polar(z) ` Return the representation of *z* in polar coordinates +:func:`rect(r, phi) ` Return the complex number *z* with polar coordinates *r* and *phi* + +**Power and logarithmic functions** +-------------------------------------------------------------------------------------------------- +:func:`exp(z) ` Return *e* raised to the power *z* +:func:`log(z[, base]) ` Return the logarithm of *z* to the given *base* (*e* by default) +:func:`log10(z) ` Return the base-10 logarithm of *z* +:func:`sqrt(z) ` Return the square root of *z* + +**Trigonometric functions** +-------------------------------------------------------------------------------------------------- +:func:`acos(z) ` Return the arc cosine of *z* +:func:`asin(z) ` Return the arc sine of *z* +:func:`atan(z) ` Return the arc tangent of *z* +:func:`cos(z) ` Return the cosine of *z* +:func:`sin(z) ` Return the sine of *z* +:func:`tan(z) ` Return the tangent of *z* + +**Hyperbolic functions** +-------------------------------------------------------------------------------------------------- +:func:`acosh(z) ` Return the inverse hyperbolic cosine of *z* +:func:`asinh(z) ` Return the inverse hyperbolic sine of *z* +:func:`atanh(z) ` Return the inverse hyperbolic tangent of *z* +:func:`cosh(z) ` Return the hyperbolic cosine of *z* +:func:`sinh(z) ` Return the hyperbolic sine of *z* +:func:`tanh(z) ` Return the hyperbolic tangent of *z* + +**Classification functions** +-------------------------------------------------------------------------------------------------- +:func:`isfinite(z) ` Check if all components of *z* are finite +:func:`isinf(z) ` Check if any component of *z* is infinite +:func:`isnan(z) ` Check if any component of *z* is a NaN +:func:`isclose(a, b, *, rel_tol, abs_tol) ` Check if the values *a* and *b* are close to each other + +**Constants** +-------------------------------------------------------------------------------------------------- +:data:`pi` *π* = 3.141592... +:data:`e` *e* = 2.718281... +:data:`tau` *τ* = 2\ *π* = 6.283185... +:data:`inf` Positive infinity +:data:`infj` Pure imaginary infinity +:data:`nan` "Not a number" (NaN) +:data:`nanj` Pure imaginary NaN +==================================================== ============================================ + + Conversions to and from polar coordinates ----------------------------------------- @@ -55,13 +106,13 @@ segment that joins the origin to *z*. The following functions can be used to convert from the native rectangular coordinates to polar coordinates and back. -.. function:: phase(x) +.. function:: phase(z) - Return the phase of *x* (also known as the *argument* of *x*), as a float. - ``phase(x)`` is equivalent to ``math.atan2(x.imag, x.real)``. The result + Return the phase of *z* (also known as the *argument* of *z*), as a float. + ``phase(z)`` is equivalent to ``math.atan2(z.imag, z.real)``. The result lies in the range [-\ *π*, *π*], and the branch cut for this operation lies along the negative real axis. The sign of the result is the same as the - sign of ``x.imag``, even when ``x.imag`` is zero:: + sign of ``z.imag``, even when ``z.imag`` is zero:: >>> phase(-1+0j) 3.141592653589793 @@ -71,147 +122,147 @@ rectangular coordinates to polar coordinates and back. .. note:: - The modulus (absolute value) of a complex number *x* can be + The modulus (absolute value) of a complex number *z* can be computed using the built-in :func:`abs` function. There is no separate :mod:`cmath` module function for this operation. -.. function:: polar(x) +.. function:: polar(z) - Return the representation of *x* in polar coordinates. Returns a - pair ``(r, phi)`` where *r* is the modulus of *x* and phi is the - phase of *x*. ``polar(x)`` is equivalent to ``(abs(x), - phase(x))``. + Return the representation of *z* in polar coordinates. Returns a + pair ``(r, phi)`` where *r* is the modulus of *z* and *phi* is the + phase of *z*. ``polar(z)`` is equivalent to ``(abs(z), + phase(z))``. .. function:: rect(r, phi) - Return the complex number *x* with polar coordinates *r* and *phi*. + Return the complex number *z* with polar coordinates *r* and *phi*. Equivalent to ``complex(r * math.cos(phi), r * math.sin(phi))``. Power and logarithmic functions ------------------------------- -.. function:: exp(x) +.. function:: exp(z) - Return *e* raised to the power *x*, where *e* is the base of natural + Return *e* raised to the power *z*, where *e* is the base of natural logarithms. -.. function:: log(x[, base]) +.. function:: log(z[, base]) - Returns the logarithm of *x* to the given *base*. If the *base* is not - specified, returns the natural logarithm of *x*. There is one branch cut, + Return the logarithm of *z* to the given *base*. If the *base* is not + specified, returns the natural logarithm of *z*. There is one branch cut, from 0 along the negative real axis to -∞. -.. function:: log10(x) +.. function:: log10(z) - Return the base-10 logarithm of *x*. This has the same branch cut as + Return the base-10 logarithm of *z*. This has the same branch cut as :func:`log`. -.. function:: sqrt(x) +.. function:: sqrt(z) - Return the square root of *x*. This has the same branch cut as :func:`log`. + Return the square root of *z*. This has the same branch cut as :func:`log`. Trigonometric functions ----------------------- -.. function:: acos(x) +.. function:: acos(z) - Return the arc cosine of *x*. There are two branch cuts: One extends right + Return the arc cosine of *z*. There are two branch cuts: One extends right from 1 along the real axis to ∞. The other extends left from -1 along the real axis to -∞. -.. function:: asin(x) +.. function:: asin(z) - Return the arc sine of *x*. This has the same branch cuts as :func:`acos`. + Return the arc sine of *z*. This has the same branch cuts as :func:`acos`. -.. function:: atan(x) +.. function:: atan(z) - Return the arc tangent of *x*. There are two branch cuts: One extends from + Return the arc tangent of *z*. There are two branch cuts: One extends from ``1j`` along the imaginary axis to ``∞j``. The other extends from ``-1j`` along the imaginary axis to ``-∞j``. -.. function:: cos(x) +.. function:: cos(z) - Return the cosine of *x*. + Return the cosine of *z*. -.. function:: sin(x) +.. function:: sin(z) - Return the sine of *x*. + Return the sine of *z*. -.. function:: tan(x) +.. function:: tan(z) - Return the tangent of *x*. + Return the tangent of *z*. Hyperbolic functions -------------------- -.. function:: acosh(x) +.. function:: acosh(z) - Return the inverse hyperbolic cosine of *x*. There is one branch cut, + Return the inverse hyperbolic cosine of *z*. There is one branch cut, extending left from 1 along the real axis to -∞. -.. function:: asinh(x) +.. function:: asinh(z) - Return the inverse hyperbolic sine of *x*. There are two branch cuts: + Return the inverse hyperbolic sine of *z*. There are two branch cuts: One extends from ``1j`` along the imaginary axis to ``∞j``. The other extends from ``-1j`` along the imaginary axis to ``-∞j``. -.. function:: atanh(x) +.. function:: atanh(z) - Return the inverse hyperbolic tangent of *x*. There are two branch cuts: One + Return the inverse hyperbolic tangent of *z*. There are two branch cuts: One extends from ``1`` along the real axis to ``∞``. The other extends from ``-1`` along the real axis to ``-∞``. -.. function:: cosh(x) +.. function:: cosh(z) - Return the hyperbolic cosine of *x*. + Return the hyperbolic cosine of *z*. -.. function:: sinh(x) +.. function:: sinh(z) - Return the hyperbolic sine of *x*. + Return the hyperbolic sine of *z*. -.. function:: tanh(x) +.. function:: tanh(z) - Return the hyperbolic tangent of *x*. + Return the hyperbolic tangent of *z*. Classification functions ------------------------ -.. function:: isfinite(x) +.. function:: isfinite(z) - Return ``True`` if both the real and imaginary parts of *x* are finite, and + Return ``True`` if both the real and imaginary parts of *z* are finite, and ``False`` otherwise. .. versionadded:: 3.2 -.. function:: isinf(x) +.. function:: isinf(z) - Return ``True`` if either the real or the imaginary part of *x* is an + Return ``True`` if either the real or the imaginary part of *z* is an infinity, and ``False`` otherwise. -.. function:: isnan(x) +.. function:: isnan(z) - Return ``True`` if either the real or the imaginary part of *x* is a NaN, + Return ``True`` if either the real or the imaginary part of *z* is a NaN, and ``False`` otherwise. diff --git a/Doc/library/cmdline.rst b/Doc/library/cmdline.rst index 78fe95a014ff7c..16c67ddbf7cec2 100644 --- a/Doc/library/cmdline.rst +++ b/Doc/library/cmdline.rst @@ -1,3 +1,5 @@ +.. _library-cmdline: + ++++++++++++++++++++++++++++++++++++ Modules command-line interface (CLI) ++++++++++++++++++++++++++++++++++++ @@ -11,9 +13,8 @@ The following modules have a command-line interface. * :mod:`code` * :ref:`compileall ` * :mod:`cProfile`: see :ref:`profile ` -* :ref:`difflib ` * :ref:`dis ` -* :mod:`doctest` +* :ref:`doctest ` * :mod:`!encodings.rot_13` * :mod:`ensurepip` * :mod:`filecmp` @@ -24,11 +25,11 @@ The following modules have a command-line interface. * :mod:`!idlelib` * :ref:`inspect ` * :ref:`json ` -* :mod:`mimetypes` +* :ref:`mimetypes ` * :mod:`pdb` -* :mod:`pickle` +* :ref:`pickle ` * :ref:`pickletools ` -* :mod:`platform` +* :ref:`platform ` * :mod:`poplib` * :ref:`profile ` * :mod:`pstats` diff --git a/Doc/library/code.rst b/Doc/library/code.rst index 8f7692df9fb22d..52587c4dd8f8e8 100644 --- a/Doc/library/code.rst +++ b/Doc/library/code.rst @@ -22,6 +22,12 @@ build applications which provide an interactive interpreter prompt. it defaults to a newly created dictionary with key ``'__name__'`` set to ``'__console__'`` and key ``'__doc__'`` set to ``None``. + Note that functions and classes objects created under an + :class:`!InteractiveInterpreter` instance will belong to the namespace + specified by *locals*. + They are only pickleable if *locals* is the namespace of an existing + module. + .. class:: InteractiveConsole(locals=None, filename="", local_exit=False) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst index a129a26190ba99..86511602fa5a60 100644 --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -55,7 +55,7 @@ any codec: The full details for each codec can also be looked up directly: -.. function:: lookup(encoding) +.. function:: lookup(encoding, /) Looks up the codec info in the Python codec registry and returns a :class:`CodecInfo` object as defined below. @@ -156,7 +156,7 @@ these additional functions which use :func:`lookup` for the codec lookup: Custom codecs are made available by registering a suitable codec search function: -.. function:: register(search_function) +.. function:: register(search_function, /) Register a codec search function. Search functions are expected to take one argument, being the encoding name in all lower case letters with hyphens @@ -168,7 +168,7 @@ function: Hyphens and spaces are converted to underscore. -.. function:: unregister(search_function) +.. function:: unregister(search_function, /) Unregister a codec search function and clear the registry's cache. If the search function is not registered, do nothing. @@ -208,6 +208,10 @@ wider range of codecs when working with binary files: .. versionchanged:: 3.11 The ``'U'`` mode has been removed. + .. deprecated:: 3.14 + + :func:`codecs.open` has been superseded by :func:`open`. + .. function:: EncodedFile(file, data_encoding, file_encoding=None, errors='strict') @@ -416,7 +420,7 @@ In addition, the following error handler is specific to the given codecs: The set of allowed values can be extended by registering a new named error handler: -.. function:: register_error(name, error_handler) +.. function:: register_error(name, error_handler, /) Register the error handling function *error_handler* under the name *name*. The *error_handler* argument will be called during encoding and decoding @@ -442,7 +446,7 @@ handler: Previously registered error handlers (including the standard error handlers) can be looked up by name: -.. function:: lookup_error(name) +.. function:: lookup_error(name, /) Return the error handler previously registered under the name *name*. @@ -1107,7 +1111,7 @@ particular, the following variants typically exist: +-----------------+--------------------------------+--------------------------------+ | cp852 | 852, IBM852 | Central and Eastern Europe | +-----------------+--------------------------------+--------------------------------+ -| cp855 | 855, IBM855 | Bulgarian, Byelorussian, | +| cp855 | 855, IBM855 | Belarusian, Bulgarian, | | | | Macedonian, Russian, Serbian | +-----------------+--------------------------------+--------------------------------+ | cp856 | | Hebrew | @@ -1155,7 +1159,7 @@ particular, the following variants typically exist: +-----------------+--------------------------------+--------------------------------+ | cp1250 | windows-1250 | Central and Eastern Europe | +-----------------+--------------------------------+--------------------------------+ -| cp1251 | windows-1251 | Bulgarian, Byelorussian, | +| cp1251 | windows-1251 | Belarusian, Bulgarian, | | | | Macedonian, Russian, Serbian | +-----------------+--------------------------------+--------------------------------+ | cp1252 | windows-1252 | Western Europe | @@ -1220,7 +1224,7 @@ particular, the following variants typically exist: +-----------------+--------------------------------+--------------------------------+ | iso8859_4 | iso-8859-4, latin4, L4 | Baltic languages | +-----------------+--------------------------------+--------------------------------+ -| iso8859_5 | iso-8859-5, cyrillic | Bulgarian, Byelorussian, | +| iso8859_5 | iso-8859-5, cyrillic | Belarusian, Bulgarian, | | | | Macedonian, Russian, Serbian | +-----------------+--------------------------------+--------------------------------+ | iso8859_6 | iso-8859-6, arabic | Arabic | @@ -1257,7 +1261,7 @@ particular, the following variants typically exist: | | | | | | | .. versionadded:: 3.5 | +-----------------+--------------------------------+--------------------------------+ -| mac_cyrillic | maccyrillic | Bulgarian, Byelorussian, | +| mac_cyrillic | maccyrillic | Belarusian, Bulgarian, | | | | Macedonian, Russian, Serbian | +-----------------+--------------------------------+--------------------------------+ | mac_greek | macgreek | Greek | diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst index 42e40de152148c..daa9af6d1dd9c9 100644 --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -28,81 +28,80 @@ An :func:`issubclass` or :func:`isinstance` test for an interface works in one of three ways. 1) A newly written class can inherit directly from one of the -abstract base classes. The class must supply the required abstract -methods. The remaining mixin methods come from inheritance and can be -overridden if desired. Other methods may be added as needed: + abstract base classes. The class must supply the required abstract + methods. The remaining mixin methods come from inheritance and can be + overridden if desired. Other methods may be added as needed: -.. testcode:: + .. testcode:: - class C(Sequence): # Direct inheritance - def __init__(self): ... # Extra method not required by the ABC - def __getitem__(self, index): ... # Required abstract method - def __len__(self): ... # Required abstract method - def count(self, value): ... # Optionally override a mixin method + class C(Sequence): # Direct inheritance + def __init__(self): ... # Extra method not required by the ABC + def __getitem__(self, index): ... # Required abstract method + def __len__(self): ... # Required abstract method + def count(self, value): ... # Optionally override a mixin method -.. doctest:: + .. doctest:: - >>> issubclass(C, Sequence) - True - >>> isinstance(C(), Sequence) - True + >>> issubclass(C, Sequence) + True + >>> isinstance(C(), Sequence) + True 2) Existing classes and built-in classes can be registered as "virtual -subclasses" of the ABCs. Those classes should define the full API -including all of the abstract methods and all of the mixin methods. -This lets users rely on :func:`issubclass` or :func:`isinstance` tests -to determine whether the full interface is supported. The exception to -this rule is for methods that are automatically inferred from the rest -of the API: + subclasses" of the ABCs. Those classes should define the full API + including all of the abstract methods and all of the mixin methods. + This lets users rely on :func:`issubclass` or :func:`isinstance` tests + to determine whether the full interface is supported. The exception to + this rule is for methods that are automatically inferred from the rest + of the API: -.. testcode:: + .. testcode:: - class D: # No inheritance - def __init__(self): ... # Extra method not required by the ABC - def __getitem__(self, index): ... # Abstract method - def __len__(self): ... # Abstract method - def count(self, value): ... # Mixin method - def index(self, value): ... # Mixin method + class D: # No inheritance + def __init__(self): ... # Extra method not required by the ABC + def __getitem__(self, index): ... # Abstract method + def __len__(self): ... # Abstract method + def count(self, value): ... # Mixin method + def index(self, value): ... # Mixin method - Sequence.register(D) # Register instead of inherit + Sequence.register(D) # Register instead of inherit -.. doctest:: + .. doctest:: - >>> issubclass(D, Sequence) - True - >>> isinstance(D(), Sequence) - True + >>> issubclass(D, Sequence) + True + >>> isinstance(D(), Sequence) + True -In this example, class :class:`!D` does not need to define -``__contains__``, ``__iter__``, and ``__reversed__`` because the -:ref:`in-operator `, the :term:`iteration ` -logic, and the :func:`reversed` function automatically fall back to -using ``__getitem__`` and ``__len__``. + In this example, class :class:`!D` does not need to define + ``__contains__``, ``__iter__``, and ``__reversed__`` because the + :ref:`in-operator `, the :term:`iteration ` + logic, and the :func:`reversed` function automatically fall back to + using ``__getitem__`` and ``__len__``. 3) Some simple interfaces are directly recognizable by the presence of -the required methods (unless those methods have been set to -:const:`None`): + the required methods (unless those methods have been set to :const:`None`): -.. testcode:: + .. testcode:: - class E: - def __iter__(self): ... - def __next__(self): ... + class E: + def __iter__(self): ... + def __next__(self): ... -.. doctest:: + .. doctest:: - >>> issubclass(E, Iterable) - True - >>> isinstance(E(), Iterable) - True + >>> issubclass(E, Iterable) + True + >>> isinstance(E(), Iterable) + True -Complex interfaces do not support this last technique because an -interface is more than just the presence of method names. Interfaces -specify semantics and relationships between methods that cannot be -inferred solely from the presence of specific method names. For -example, knowing that a class supplies ``__getitem__``, ``__len__``, and -``__iter__`` is insufficient for distinguishing a :class:`Sequence` from -a :class:`Mapping`. + Complex interfaces do not support this last technique because an + interface is more than just the presence of method names. Interfaces + specify semantics and relationships between methods that cannot be + inferred solely from the presence of specific method names. For + example, knowing that a class supplies ``__getitem__``, ``__len__``, and + ``__iter__`` is insufficient for distinguishing a :class:`Sequence` from + a :class:`Mapping`. .. versionadded:: 3.9 These abstract classes now support ``[]``. See :ref:`types-genericalias` diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index 5b4e445762e076..5fbdb12f40cafa 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -748,8 +748,8 @@ stack manipulations such as ``dup``, ``drop``, ``swap``, ``over``, ``pick``, returns or raises is then returned or raised by :meth:`~object.__getitem__`. Note that :meth:`__missing__` is *not* called for any operations besides - :meth:`~object.__getitem__`. This means that :meth:`get` will, like normal - dictionaries, return ``None`` as a default rather than using + :meth:`~object.__getitem__`. This means that :meth:`~dict.get` will, like + normal dictionaries, return ``None`` as a default rather than using :attr:`default_factory`. @@ -849,8 +849,9 @@ they add the ability to access fields by name instead of position index. Returns a new tuple subclass named *typename*. The new subclass is used to create tuple-like objects that have fields accessible by attribute lookup as well as being indexable and iterable. Instances of the subclass also have a - helpful docstring (with typename and field_names) and a helpful :meth:`__repr__` - method which lists the tuple contents in a ``name=value`` format. + helpful docstring (with *typename* and *field_names*) and a helpful + :meth:`~object.__repr__` method which lists the tuple contents in a ``name=value`` + format. The *field_names* are a sequence of strings such as ``['x', 'y']``. Alternatively, *field_names* can be a single string with each fieldname @@ -894,10 +895,10 @@ they add the ability to access fields by name instead of position index. Added the *module* parameter. .. versionchanged:: 3.7 - Removed the *verbose* parameter and the :attr:`_source` attribute. + Removed the *verbose* parameter and the :attr:`!_source` attribute. .. versionchanged:: 3.7 - Added the *defaults* parameter and the :attr:`_field_defaults` + Added the *defaults* parameter and the :attr:`~somenamedtuple._field_defaults` attribute. .. doctest:: @@ -1109,7 +1110,7 @@ Some differences from :class:`dict` still remain: A regular :class:`dict` can emulate the order sensitive equality test with ``p == q and all(k1 == k2 for k1, k2 in zip(p, q))``. -* The :meth:`popitem` method of :class:`OrderedDict` has a different +* The :meth:`~OrderedDict.popitem` method of :class:`OrderedDict` has a different signature. It accepts an optional argument to specify which item is popped. A regular :class:`dict` can emulate OrderedDict's ``od.popitem(last=True)`` @@ -1119,7 +1120,7 @@ Some differences from :class:`dict` still remain: with ``(k := next(iter(d)), d.pop(k))`` which will return and remove the leftmost (first) item if it exists. -* :class:`OrderedDict` has a :meth:`move_to_end` method to efficiently +* :class:`OrderedDict` has a :meth:`~OrderedDict.move_to_end` method to efficiently reposition an element to an endpoint. A regular :class:`dict` can emulate OrderedDict's ``od.move_to_end(k, @@ -1130,7 +1131,7 @@ Some differences from :class:`dict` still remain: OrderedDict's ``od.move_to_end(k, last=False)`` which moves the key and its associated value to the leftmost (first) position. -* Until Python 3.8, :class:`dict` lacked a :meth:`__reversed__` method. +* Until Python 3.8, :class:`dict` lacked a :meth:`~object.__reversed__` method. .. class:: OrderedDict([items]) @@ -1185,7 +1186,7 @@ anywhere a regular dictionary is used. .. versionchanged:: 3.6 With the acceptance of :pep:`468`, order is retained for keyword arguments - passed to the :class:`OrderedDict` constructor and its :meth:`update` + passed to the :class:`OrderedDict` constructor and its :meth:`~dict.update` method. .. versionchanged:: 3.9 diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 5a950081a1c98d..3c8d9ab111e09e 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -6,8 +6,9 @@ .. versionadded:: 3.2 -**Source code:** :source:`Lib/concurrent/futures/thread.py` -and :source:`Lib/concurrent/futures/process.py` +**Source code:** :source:`Lib/concurrent/futures/thread.py`, +:source:`Lib/concurrent/futures/process.py`, +and :source:`Lib/concurrent/futures/interpreter.py` -------------- @@ -40,11 +41,14 @@ Executor Objects future = executor.submit(pow, 323, 1235) print(future.result()) - .. method:: map(fn, *iterables, timeout=None, chunksize=1) + .. method:: map(fn, *iterables, timeout=None, chunksize=1, buffersize=None) Similar to :func:`map(fn, *iterables) ` except: - * the *iterables* are collected immediately rather than lazily; + * The *iterables* are collected immediately rather than lazily, unless a + *buffersize* is specified to limit the number of submitted tasks whose + results have not yet been yielded. If the buffer is full, iteration over + the *iterables* pauses until a result is yielded from the buffer. * *fn* is executed asynchronously and several calls to *fn* may be made concurrently. @@ -68,7 +72,10 @@ Executor Objects *chunksize* has no effect. .. versionchanged:: 3.5 - Added the *chunksize* argument. + Added the *chunksize* parameter. + + .. versionchanged:: 3.14 + Added the *buffersize* parameter. .. method:: shutdown(wait=True, *, cancel_futures=False) @@ -292,7 +299,7 @@ the bytes over a shared :mod:`socket ` or The optional *initializer* and *initargs* arguments have the same meaning as for :class:`!ThreadPoolExecutor`: the initializer is run - when each worker is created, though in this case it is run.in + when each worker is created, though in this case it is run in the worker's interpreter. The executor serializes the *initializer* and *initargs* using :mod:`pickle` when sending them to the worker's interpreter. @@ -415,6 +422,30 @@ to a :class:`ProcessPoolExecutor` will result in deadlock. require the *fork* start method for :class:`ProcessPoolExecutor` you must explicitly pass ``mp_context=multiprocessing.get_context("fork")``. + .. method:: terminate_workers() + + Attempt to terminate all living worker processes immediately by calling + :meth:`Process.terminate ` on each of them. + Internally, it will also call :meth:`Executor.shutdown` to ensure that all + other resources associated with the executor are freed. + + After calling this method the caller should no longer submit tasks to the + executor. + + .. versionadded:: 3.14 + + .. method:: kill_workers() + + Attempt to kill all living worker processes immediately by calling + :meth:`Process.kill ` on each of them. + Internally, it will also call :meth:`Executor.shutdown` to ensure that all + other resources associated with the executor are freed. + + After calling this method the caller should no longer submit tasks to the + executor. + + .. versionadded:: 3.14 + .. _processpoolexecutor-example: ProcessPoolExecutor Example diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index ac0f3fca3d72fd..bb109a9b742cb7 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1244,6 +1244,10 @@ ConfigParser Objects *space_around_delimiters* is true, delimiters between keys and values are surrounded by spaces. + .. versionchanged:: 3.14 + Raises InvalidWriteError if this would write a representation which cannot + be accurately parsed by a future :meth:`read` call from this parser. + .. note:: Comments in the original configuration file are not preserved when @@ -1459,6 +1463,17 @@ Exceptions .. versionadded:: 3.14 +.. exception:: InvalidWriteError + + Exception raised when an attempted :meth:`ConfigParser.write` would not be parsed + accurately with a future :meth:`ConfigParser.read` call. + + Ex: Writing a key beginning with the :attr:`ConfigParser.SECTCRE` pattern + would parse as a section header when read. Attempting to write this will raise + this exception. + + .. versionadded:: 3.14 + .. rubric:: Footnotes .. [1] Config parsers allow for heavy customization. If you are interested in diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst index 04bb8c51a3b197..c0ac4ea8412ebd 100644 --- a/Doc/library/constants.rst +++ b/Doc/library/constants.rst @@ -46,11 +46,12 @@ A small number of constants live in the built-in namespace. They are: See :ref:`implementing-the-arithmetic-operations` for examples. - .. note:: + .. caution:: - ``NotImplementedError`` and :data:`!NotImplemented` are not interchangeable, - even though they have similar names and purposes. - See :exc:`NotImplementedError` for details on when to use it. + :data:`!NotImplemented` and :exc:`!NotImplementedError` are not + interchangeable. This constant should only be used as described + above; see :exc:`NotImplementedError` for details on correct usage + of the exception. .. versionchanged:: 3.9 Evaluating :data:`!NotImplemented` in a boolean context was deprecated. diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index e8f264f949807d..176be4ff333955 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -49,7 +49,7 @@ Functions and classes provided: While many objects natively support use in with statements, sometimes a resource needs to be managed that isn't a context manager in its own right, - and doesn't implement a ``close()`` method for use with ``contextlib.closing`` + and doesn't implement a ``close()`` method for use with ``contextlib.closing``. An abstract example would be the following to ensure correct resource management:: @@ -629,7 +629,8 @@ Functions and classes provided: The :meth:`~ExitStack.close` method is not implemented; :meth:`aclose` must be used instead. - .. coroutinemethod:: enter_async_context(cm) + .. method:: enter_async_context(cm) + :async: Similar to :meth:`ExitStack.enter_context` but expects an asynchronous context manager. @@ -647,7 +648,8 @@ Functions and classes provided: Similar to :meth:`ExitStack.callback` but expects a coroutine function. - .. coroutinemethod:: aclose() + .. method:: aclose() + :async: Similar to :meth:`ExitStack.close` but properly handles awaitables. diff --git a/Doc/library/contextvars.rst b/Doc/library/contextvars.rst index 3e3b30c724c631..57580ce026e96a 100644 --- a/Doc/library/contextvars.rst +++ b/Doc/library/contextvars.rst @@ -112,7 +112,7 @@ Context Variables assert var.get() == 'default value' - .. versionadded:: next + .. versionadded:: 3.14 Added support for usage as a context manager. diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index bf89700f54b7e9..5b733d5321e907 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -657,12 +657,13 @@ Nested structures can also be initialized in the constructor in several ways:: >>> r = RECT((1, 2), (3, 4)) Field :term:`descriptor`\s can be retrieved from the *class*, they are useful -for debugging because they can provide useful information:: +for debugging because they can provide useful information. +See :class:`CField`:: - >>> print(POINT.x) - - >>> print(POINT.y) - + >>> POINT.x + + >>> POINT.y + >>> @@ -1778,7 +1779,8 @@ in :mod:`!ctypes`) which inherits from the private :class:`_CFuncPtr` class: .. audit-event:: ctypes.call_function func_pointer,arguments foreign-functions - Some ways to invoke foreign function calls may raise an auditing event + Some ways to invoke foreign function calls as well as some of the + functions in this module may raise an auditing event ``ctypes.call_function`` with arguments ``function pointer`` and ``arguments``. .. _ctypes-function-prototypes: @@ -2170,10 +2172,20 @@ Utility functions .. function:: POINTER(type, /) - Create and return a new ctypes pointer type. Pointer types are cached and + Create or return a ctypes pointer type. Pointer types are cached and reused internally, so calling this function repeatedly is cheap. *type* must be a ctypes type. + .. impl-detail:: + + The resulting pointer type is cached in the ``__pointer_type__`` + attribute of *type*. + It is possible to set this attribute before the first call to + ``POINTER`` in order to set a custom pointer type. + However, doing this is discouraged: manually creating a suitable + pointer type is difficult without relying on implementation + details that may change in future Python versions. + .. function:: pointer(obj, /) @@ -2338,6 +2350,16 @@ Data types library. *name* is the name of the symbol that exports the data, *library* is the loaded shared library. + Common class variables of ctypes data types: + + .. attribute:: __pointer_type__ + + The pointer type that was created by calling + :func:`POINTER` for corresponding ctypes data type. If a pointer type + was not yet created, the attribute is missing. + + .. versionadded:: 3.14 + Common instance variables of ctypes data types: .. attribute:: _b_base_ @@ -2631,6 +2653,9 @@ These are the fundamental ctypes data types: Represents the C :c:expr:`PyObject *` datatype. Calling this without an argument creates a ``NULL`` :c:expr:`PyObject *` pointer. + .. versionchanged:: 3.14 + :class:`!py_object` is now a :term:`generic type`. + The :mod:`!ctypes.wintypes` module provides quite some other Windows specific data types, for example :c:type:`!HWND`, :c:type:`!WPARAM`, or :c:type:`!DWORD`. Some useful structures like :c:type:`!MSG` or :c:type:`!RECT` are also defined. @@ -2729,6 +2754,16 @@ fields, or any other data types containing pointer type fields. when :attr:`_fields_` is assigned, otherwise it will have no effect. Setting this attribute to 0 is the same as not setting it at all. + This is only implemented for the MSVC-compatible memory layout. + + .. deprecated-removed:: 3.14 3.19 + + For historical reasons, if :attr:`!_pack_` is non-zero, + the MSVC-compatible layout will be used by default. + On non-Windows platforms, this default is deprecated and is slated to + become an error in Python 3.19. + If it is intended, set :attr:`~Structure._layout_` to ``'ms'`` + explicitly. .. attribute:: _align_ @@ -2757,12 +2792,15 @@ fields, or any other data types containing pointer type fields. Currently the default will be: - On Windows: ``"ms"`` - - When :attr:`~Structure._pack_` is specified: ``"ms"`` + - When :attr:`~Structure._pack_` is specified: ``"ms"``. + (This is deprecated; see :attr:`~Structure._pack_` documentation.) - Otherwise: ``"gcc-sysv"`` :attr:`!_layout_` must already be defined when :attr:`~Structure._fields_` is assigned, otherwise it will have no effect. + .. versionadded:: 3.14 + .. attribute:: _anonymous_ An optional sequence that lists the names of unnamed (anonymous) fields. @@ -2812,6 +2850,98 @@ fields, or any other data types containing pointer type fields. present in :attr:`_fields_`. +.. class:: CField(*args, **kw) + + Descriptor for fields of a :class:`Structure` and :class:`Union`. + For example:: + + >>> class Color(Structure): + ... _fields_ = ( + ... ('red', c_uint8), + ... ('green', c_uint8), + ... ('blue', c_uint8), + ... ('intense', c_bool, 1), + ... ('blinking', c_bool, 1), + ... ) + ... + >>> Color.red + + >>> Color.green.type + + >>> Color.blue.byte_offset + 2 + >>> Color.intense + + >>> Color.blinking.bit_offset + 1 + + All attributes are read-only. + + :class:`!CField` objects are created via :attr:`~Structure._fields_`; + do not instantiate the class directly. + + .. versionadded:: 3.14 + + Previously, descriptors only had ``offset`` and ``size`` attributes + and a readable string representation; the :class:`!CField` class was not + available directly. + + .. attribute:: name + + Name of the field, as a string. + + .. attribute:: type + + Type of the field, as a :ref:`ctypes class `. + + .. attribute:: offset + byte_offset + + Offset of the field, in bytes. + + For bitfields, this is the offset of the underlying byte-aligned + *storage unit*; see :attr:`~CField.bit_offset`. + + .. attribute:: byte_size + + Size of the field, in bytes. + + For bitfields, this is the size of the underlying *storage unit*. + Typically, it has the same size as the bitfield's type. + + .. attribute:: size + + For non-bitfields, equivalent to :attr:`~CField.byte_size`. + + For bitfields, this contains a backwards-compatible bit-packed + value that combines :attr:`~CField.bit_size` and + :attr:`~CField.bit_offset`. + Prefer using the explicit attributes instead. + + .. attribute:: is_bitfield + + True if this is a bitfield. + + .. attribute:: bit_offset + bit_size + + The location of a bitfield within its *storage unit*, that is, within + :attr:`~CField.byte_size` bytes of memory starting at + :attr:`~CField.byte_offset`. + + To get the field's value, read the storage unit as an integer, + :ref:`shift left ` by :attr:`!bit_offset` and + take the :attr:`!bit_size` least significant bits. + + For non-bitfields, :attr:`!bit_offset` is zero + and :attr:`!bit_size` is equal to ``byte_size * 8``. + + .. attribute:: is_anonymous + + True if this field is anonymous, that is, it contains nested sub-fields + that should be be merged into a containing structure or union. + + .. _ctypes-arrays-pointers: Arrays and pointers diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 6c7fc721a3e0fb..137504c51b4358 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -68,6 +68,21 @@ The module :mod:`curses` defines the following exception: The module :mod:`curses` defines the following functions: +.. function:: assume_default_colors(fg, bg) + + Allow use of default values for colors on terminals supporting this feature. + Use this to support transparency in your application. + + * Assign terminal default foreground/background colors to color number ``-1``. + So ``init_pair(x, COLOR_RED, -1)`` will initialize pair *x* as red + on default background and ``init_pair(x, -1, COLOR_BLUE)`` will + initialize pair *x* as default foreground on blue. + + * Change the definition of the color-pair ``0`` to ``(fg, bg)``. + + .. versionadded:: 3.14 + + .. function:: baudrate() Return the output speed of the terminal in bits per second. On software @@ -290,9 +305,11 @@ The module :mod:`curses` defines the following functions: Change the definition of a color-pair. It takes three arguments: the number of the color-pair to be changed, the foreground color number, and the background color number. The value of *pair_number* must be between ``1`` and - ``COLOR_PAIRS - 1`` (the ``0`` color pair is wired to white on black and cannot - be changed). The value of *fg* and *bg* arguments must be between ``0`` and - ``COLORS - 1``, or, after calling :func:`use_default_colors`, ``-1``. + ``COLOR_PAIRS - 1`` (the ``0`` color pair can only be changed by + :func:`use_default_colors` and :func:`assume_default_colors`). + The value of *fg* and *bg* arguments must be between ``0`` and + ``COLORS - 1``, or, after calling :func:`!use_default_colors` or + :func:`!assume_default_colors`, ``-1``. If the color-pair was previously initialized, the screen is refreshed and all occurrences of that color-pair are changed to the new definition. @@ -678,11 +695,7 @@ The module :mod:`curses` defines the following functions: .. function:: use_default_colors() - Allow use of default values for colors on terminals supporting this feature. Use - this to support transparency in your application. The default color is assigned - to the color number ``-1``. After calling this function, ``init_pair(x, - curses.COLOR_RED, -1)`` initializes, for instance, color pair *x* to a red - foreground color on the default background. + Equivalent to ``assume_default_colors(-1, -1)``. .. function:: wrapper(func, /, *args, **kwargs) diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index f63a01e9570791..f18c7cc9c02da6 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -164,7 +164,7 @@ Module contents - *match_args*: If true (the default is ``True``), the :attr:`~object.__match_args__` tuple will be created from the list of - parameters to the generated :meth:`~object.__init__` method (even if + non keyword-only parameters to the generated :meth:`~object.__init__` method (even if :meth:`!__init__` is not generated, see above). If false, or if :attr:`!__match_args__` is already defined in the class, then :attr:`!__match_args__` will not be generated. @@ -175,11 +175,12 @@ Module contents fields will be marked as keyword-only. If a field is marked as keyword-only, then the only effect is that the :meth:`~object.__init__` parameter generated from a keyword-only field must be specified - with a keyword when :meth:`!__init__` is called. There is no - effect on any other aspect of dataclasses. See the - :term:`parameter` glossary entry for details. Also see the + with a keyword when :meth:`!__init__` is called. See the :term:`parameter` + glossary entry for details. Also see the :const:`KW_ONLY` section. + Keyword-only fields are not included in :attr:`!__match_args__`. + .. versionadded:: 3.10 - *slots*: If true (the default is ``False``), :attr:`~object.__slots__` attribute @@ -299,11 +300,13 @@ Module contents This is used when the generated :meth:`~object.__init__` method's parameters are computed. + Keyword-only fields are also not included in :attr:`!__match_args__`. + .. versionadded:: 3.10 - - ``doc``: optional docstring for this field. + - *doc*: optional docstring for this field. - .. versionadded:: 3.13 + .. versionadded:: 3.14 If the default value of a field is specified by a call to :func:`!field`, then the class attribute for this field will be @@ -341,6 +344,15 @@ Module contents Other attributes may exist, but they are private and must not be inspected or relied on. +.. class:: InitVar + + ``InitVar[T]`` type annotations describe variables that are :ref:`init-only + `. Fields annotated with :class:`!InitVar` + are considered pseudo-fields, and thus are neither returned by the + :func:`fields` function nor used in any way except adding them as + parameters to :meth:`~object.__init__` and an optional + :meth:`__post_init__`. + .. function:: fields(class_or_instance) Returns a tuple of :class:`Field` objects that define the fields for this @@ -597,8 +609,8 @@ Init-only variables Another place where :func:`@dataclass ` inspects a type annotation is to determine if a field is an init-only variable. It does this by seeing -if the type of a field is of type ``dataclasses.InitVar``. If a field -is an ``InitVar``, it is considered a pseudo-field called an init-only +if the type of a field is of type :class:`InitVar`. If a field +is an :class:`InitVar`, it is considered a pseudo-field called an init-only field. As it is not a true field, it is not returned by the module-level :func:`fields` function. Init-only fields are added as parameters to the generated :meth:`~object.__init__` method, and are passed to diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 1af7d6be750102..3470f42a6c622d 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -261,6 +261,22 @@ A :class:`timedelta` object represents a duration, the difference between two >>> (d.days, d.seconds, d.microseconds) (-1, 86399, 999999) + Since the string representation of :class:`!timedelta` objects can be confusing, + use the following recipe to produce a more readable format: + + .. code-block:: pycon + + >>> def pretty_timedelta(td): + ... if td.days >= 0: + ... return str(td) + ... return f'-({-td!s})' + ... + >>> d = timedelta(hours=-1) + >>> str(d) # not human-friendly + '-1 day, 23:00:00' + >>> pretty_timedelta(d) + '-(1:00:00)' + Class attributes: @@ -699,8 +715,8 @@ Instance methods: .. method:: date.replace(year=self.year, month=self.month, day=self.day) - Return a date with the same value, except for those parameters given new - values by whichever keyword arguments are specified. + Return a new :class:`date` object with the same values, but with specified + parameters updated. Example:: @@ -709,8 +725,8 @@ Instance methods: >>> d.replace(day=26) datetime.date(2002, 12, 26) - :class:`date` objects are also supported by generic function - :func:`copy.replace`. + The generic function :func:`copy.replace` also supports :class:`date` + objects. .. method:: date.timetuple() @@ -1348,10 +1364,10 @@ Instance methods: hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond, \ tzinfo=self.tzinfo, *, fold=0) - Return a datetime with the same attributes, except for those attributes given - new values by whichever keyword arguments are specified. Note that - ``tzinfo=None`` can be specified to create a naive datetime from an aware - datetime with no conversion of date and time data. + Return a new :class:`datetime` object with the same attributes, but with + specified parameters updated. Note that ``tzinfo=None`` can be specified to + create a naive datetime from an aware datetime with no conversion of date + and time data. :class:`.datetime` objects are also supported by generic function :func:`copy.replace`. @@ -1942,10 +1958,10 @@ Instance methods: .. method:: time.replace(hour=self.hour, minute=self.minute, second=self.second, \ microsecond=self.microsecond, tzinfo=self.tzinfo, *, fold=0) - Return a :class:`.time` with the same value, except for those attributes given - new values by whichever keyword arguments are specified. Note that - ``tzinfo=None`` can be specified to create a naive :class:`.time` from an - aware :class:`.time`, without conversion of the time data. + Return a new :class:`.time` with the same values, but with specified + parameters updated. Note that ``tzinfo=None`` can be specified to create a + naive :class:`.time` from an aware :class:`.time`, without conversion of the + time data. :class:`.time` objects are also supported by generic function :func:`copy.replace`. diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index 9318af60b60f95..10ddfa02b43156 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -2,7 +2,7 @@ ===================================================================== .. module:: decimal - :synopsis: Implementation of the General Decimal Arithmetic Specification. + :synopsis: Implementation of the General Decimal Arithmetic Specification. .. moduleauthor:: Eric Price .. moduleauthor:: Facundo Batista @@ -121,7 +121,7 @@ reset them before monitoring a calculation. .. _decimal-tutorial: -Quick-start Tutorial +Quick-start tutorial -------------------- The usual start to using decimals is importing the module, viewing the current @@ -367,6 +367,8 @@ Decimal objects appears above. These include decimal digits from various other alphabets (for example, Arabic-Indic and Devanāgarī digits) along with the fullwidth digits ``'\uff10'`` through ``'\uff19'``. + Case is not significant, so, for example, ``inf``, ``Inf``, ``INFINITY``, + and ``iNfINity`` are all acceptable spellings for positive infinity. If *value* is a :class:`tuple`, it should have three components, a sign (``0`` for positive or ``1`` for negative), a :class:`tuple` of @@ -1029,6 +1031,14 @@ function to temporarily change the active context. .. versionchanged:: 3.11 :meth:`localcontext` now supports setting context attributes through the use of keyword arguments. +.. function:: IEEEContext(bits) + + Return a context object initialized to the proper values for one of the + IEEE interchange formats. The argument must be a multiple of 32 and less + than :const:`IEEE_CONTEXT_MAX_BITS`. + + .. versionadded:: 3.14 + New contexts can also be created using the :class:`Context` constructor described below. In addition, the module provides three pre-made contexts: @@ -1086,40 +1096,52 @@ In addition to the three supplied contexts, new contexts can be created with the default values are copied from the :const:`DefaultContext`. If the *flags* field is not specified or is :const:`None`, all flags are cleared. - *prec* is an integer in the range [``1``, :const:`MAX_PREC`] that sets - the precision for arithmetic operations in the context. + .. attribute:: prec + + An integer in the range [``1``, :const:`MAX_PREC`] that sets + the precision for arithmetic operations in the context. + + .. attribute:: rounding + + One of the constants listed in the section `Rounding Modes`_. - The *rounding* option is one of the constants listed in the section - `Rounding Modes`_. + .. attribute:: traps + flags - The *traps* and *flags* fields list any signals to be set. Generally, new - contexts should only set traps and leave the flags clear. + Lists of any signals to be set. Generally, new contexts should only set + traps and leave the flags clear. - The *Emin* and *Emax* fields are integers specifying the outer limits allowable - for exponents. *Emin* must be in the range [:const:`MIN_EMIN`, ``0``], - *Emax* in the range [``0``, :const:`MAX_EMAX`]. + .. attribute:: Emin + Emax - The *capitals* field is either ``0`` or ``1`` (the default). If set to - ``1``, exponents are printed with a capital ``E``; otherwise, a - lowercase ``e`` is used: ``Decimal('6.02e+23')``. + Integers specifying the outer limits allowable for exponents. *Emin* must + be in the range [:const:`MIN_EMIN`, ``0``], *Emax* in the range + [``0``, :const:`MAX_EMAX`]. - The *clamp* field is either ``0`` (the default) or ``1``. - If set to ``1``, the exponent ``e`` of a :class:`Decimal` - instance representable in this context is strictly limited to the - range ``Emin - prec + 1 <= e <= Emax - prec + 1``. If *clamp* is - ``0`` then a weaker condition holds: the adjusted exponent of - the :class:`Decimal` instance is at most :attr:`~Context.Emax`. When *clamp* is - ``1``, a large normal number will, where possible, have its - exponent reduced and a corresponding number of zeros added to its - coefficient, in order to fit the exponent constraints; this - preserves the value of the number but loses information about - significant trailing zeros. For example:: + .. attribute:: capitals - >>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999') - Decimal('1.23000E+999') + Either ``0`` or ``1`` (the default). If set to + ``1``, exponents are printed with a capital ``E``; otherwise, a + lowercase ``e`` is used: ``Decimal('6.02e+23')``. - A *clamp* value of ``1`` allows compatibility with the - fixed-width decimal interchange formats specified in IEEE 754. + .. attribute:: clamp + + Either ``0`` (the default) or ``1``. If set to ``1``, the exponent ``e`` + of a :class:`Decimal` instance representable in this context is strictly + limited to the range ``Emin - prec + 1 <= e <= Emax - prec + 1``. + If *clamp* is ``0`` then a weaker condition holds: the adjusted exponent of + the :class:`Decimal` instance is at most :attr:`~Context.Emax`. When *clamp* is + ``1``, a large normal number will, where possible, have its + exponent reduced and a corresponding number of zeros added to its + coefficient, in order to fit the exponent constraints; this + preserves the value of the number but loses information about + significant trailing zeros. For example:: + + >>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999') + Decimal('1.23000E+999') + + A *clamp* value of ``1`` allows compatibility with the + fixed-width decimal interchange formats specified in IEEE 754. The :class:`Context` class defines several general purpose methods as well as a large number of methods for doing arithmetic directly in a given context. @@ -1550,18 +1572,19 @@ Constants The constants in this section are only relevant for the C module. They are also included in the pure Python version for compatibility. -+---------------------+---------------------+-------------------------------+ -| | 32-bit | 64-bit | -+=====================+=====================+===============================+ -| .. data:: MAX_PREC | ``425000000`` | ``999999999999999999`` | -+---------------------+---------------------+-------------------------------+ -| .. data:: MAX_EMAX | ``425000000`` | ``999999999999999999`` | -+---------------------+---------------------+-------------------------------+ -| .. data:: MIN_EMIN | ``-425000000`` | ``-999999999999999999`` | -+---------------------+---------------------+-------------------------------+ -| .. data:: MIN_ETINY | ``-849999999`` | ``-1999999999999999997`` | -+---------------------+---------------------+-------------------------------+ - ++---------------------------------+---------------------+-------------------------------+ +| | 32-bit | 64-bit | ++=================================+=====================+===============================+ +| .. data:: MAX_PREC | ``425000000`` | ``999999999999999999`` | ++---------------------------------+---------------------+-------------------------------+ +| .. data:: MAX_EMAX | ``425000000`` | ``999999999999999999`` | ++---------------------------------+---------------------+-------------------------------+ +| .. data:: MIN_EMIN | ``-425000000`` | ``-999999999999999999`` | ++---------------------------------+---------------------+-------------------------------+ +| .. data:: MIN_ETINY | ``-849999999`` | ``-1999999999999999997`` | ++---------------------------------+---------------------+-------------------------------+ +| .. data:: IEEE_CONTEXT_MAX_BITS | ``256`` | ``512`` | ++---------------------------------+---------------------+-------------------------------+ .. data:: HAVE_THREADS @@ -1758,7 +1781,7 @@ The following table summarizes the hierarchy of signals:: .. _decimal-notes: -Floating-Point Notes +Floating-point notes -------------------- @@ -1884,13 +1907,20 @@ the current thread. If :func:`setcontext` has not been called before :func:`getcontext`, then :func:`getcontext` will automatically create a new context for use in the -current thread. - -The new context is copied from a prototype context called *DefaultContext*. To -control the defaults so that each thread will use the same values throughout the -application, directly modify the *DefaultContext* object. This should be done -*before* any threads are started so that there won't be a race condition between -threads calling :func:`getcontext`. For example:: +current thread. New context objects have default values set from the +:data:`decimal.DefaultContext` object. + +The :data:`sys.flags.thread_inherit_context` flag affects the context for +new threads. If the flag is false, new threads will start with an empty +context. In this case, :func:`getcontext` will create a new context object +when called and use the default values from *DefaultContext*. If the flag +is true, new threads will start with a copy of context from the caller of +:meth:`threading.Thread.start`. + +To control the defaults so that each thread will use the same values throughout +the application, directly modify the *DefaultContext* object. This should be +done *before* any threads are started so that there won't be a race condition +between threads calling :func:`getcontext`. For example:: # Set applicationwide defaults for all threads about to be launched DefaultContext.prec = 12 diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index e0e7286214ac11..44767b5dd2d5c9 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -76,7 +76,7 @@ the following command can be used to display the disassembly of 2 RESUME 0 3 LOAD_GLOBAL 1 (len + NULL) - LOAD_FAST 0 (alist) + LOAD_FAST_BORROW 0 (alist) CALL 1 RETURN_VALUE @@ -105,18 +105,26 @@ The following options are accepted: Show inline caches. + .. versionadded:: 3.13 + .. option:: -O, --show-offsets Show offsets of instructions. + .. versionadded:: 3.13 + .. option:: -P, --show-positions Show positions of instructions in the source code. + .. versionadded:: 3.14 + .. option:: -S, --specialized Show specialized bytecode. + .. versionadded:: 3.14 + If :file:`infile` is specified, its disassembled code will be written to stdout. Otherwise, disassembly is performed on compiled source code received from stdin. @@ -207,7 +215,7 @@ Example: ... RESUME LOAD_GLOBAL - LOAD_FAST + LOAD_FAST_BORROW CALL RETURN_VALUE @@ -527,7 +535,7 @@ details of bytecode instructions as :class:`Instruction` instances: :class:`dis.Positions` object holding the start and end locations that are covered by this instruction. - .. data::cache_info + .. data:: cache_info Information about the cache entries of this instruction, as triplets of the form ``(name, size, data)``, where the ``name`` @@ -1346,9 +1354,6 @@ iterations of the loop. If ``STACK[-1]`` is not ``None``, increments the bytecode counter by *delta*. ``STACK[-1]`` is popped. - This opcode is a pseudo-instruction, replaced in final bytecode by - the directed versions (forward/backward). - .. versionadded:: 3.11 .. versionchanged:: 3.12 @@ -1360,9 +1365,6 @@ iterations of the loop. If ``STACK[-1]`` is ``None``, increments the bytecode counter by *delta*. ``STACK[-1]`` is popped. - This opcode is a pseudo-instruction, replaced in final bytecode by - the directed versions (forward/backward). - .. versionadded:: 3.11 .. versionchanged:: 3.12 @@ -1394,6 +1396,13 @@ iterations of the loop. This opcode is now only used in situations where the local variable is guaranteed to be initialized. It cannot raise :exc:`UnboundLocalError`. +.. opcode:: LOAD_FAST_BORROW (var_num) + + Pushes a borrowed reference to the local ``co_varnames[var_num]`` onto the + stack. + + .. versionadded:: 3.14 + .. opcode:: LOAD_FAST_LOAD_FAST (var_nums) Pushes references to ``co_varnames[var_nums >> 4]`` and @@ -1401,6 +1410,14 @@ iterations of the loop. .. versionadded:: 3.13 + +.. opcode:: LOAD_FAST_BORROW_LOAD_FAST_BORROW (var_nums) + + Pushes borrowed references to ``co_varnames[var_nums >> 4]`` and + ``co_varnames[var_nums & 15]`` onto the stack. + + .. versionadded:: 3.14 + .. opcode:: LOAD_FAST_CHECK (var_num) Pushes a reference to the local ``co_varnames[var_num]`` onto the stack, @@ -1650,7 +1667,7 @@ iterations of the loop. * ``oparg == 2``: call :func:`repr` on *value* * ``oparg == 3``: call :func:`ascii` on *value* - Used for implementing formatted literal strings (f-strings). + Used for implementing formatted string literals (f-strings). .. versionadded:: 3.13 @@ -1663,7 +1680,7 @@ iterations of the loop. result = value.__format__("") STACK.append(result) - Used for implementing formatted literal strings (f-strings). + Used for implementing formatted string literals (f-strings). .. versionadded:: 3.13 @@ -1676,7 +1693,7 @@ iterations of the loop. result = value.__format__(spec) STACK.append(result) - Used for implementing formatted literal strings (f-strings). + Used for implementing formatted string literals (f-strings). .. versionadded:: 3.13 @@ -2015,4 +2032,3 @@ instructions: .. deprecated:: 3.13 All jumps are now relative. This list is empty. - diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst index 106b0a6c95b7be..b86fef9fd6f310 100644 --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -177,15 +177,8 @@ prohibit it by passing ``verbose=False``. In either of those cases, ``sys.argv`` is not examined by :func:`testmod` (so passing ``-v`` or not has no effect). -There is also a command line shortcut for running :func:`testmod`. You can -instruct the Python interpreter to run the doctest module directly from the -standard library and pass the module name(s) on the command line:: - - python -m doctest -v example.py - -This will import :file:`example.py` as a standalone module and run -:func:`testmod` on it. Note that this may not work correctly if the file is -part of a package and imports other submodules from that package. +There is also a command line shortcut for running :func:`testmod`, see section +:ref:`doctest-cli`. For more information on :func:`testmod`, see section :ref:`doctest-basic-api`. @@ -248,16 +241,53 @@ Like :func:`testmod`, :func:`testfile`'s verbosity can be set with the ``-v`` command-line switch or with the optional keyword argument *verbose*. -There is also a command line shortcut for running :func:`testfile`. You can -instruct the Python interpreter to run the doctest module directly from the -standard library and pass the file name(s) on the command line:: +There is also a command line shortcut for running :func:`testfile`, see section +:ref:`doctest-cli`. - python -m doctest -v example.txt +For more information on :func:`testfile`, see section :ref:`doctest-basic-api`. -Because the file name does not end with :file:`.py`, :mod:`doctest` infers that -it must be run with :func:`testfile`, not :func:`testmod`. -For more information on :func:`testfile`, see section :ref:`doctest-basic-api`. +.. _doctest-cli: + +Command-line Usage +------------------ + +The :mod:`doctest` module can be invoked as a script from the command line: + +.. code-block:: bash + + python -m doctest [-v] [-o OPTION] [-f] file [file ...] + +.. program:: doctest + +.. option:: -v, --verbose + + Detailed report of all examples tried is printed to standard output, + along with assorted summaries at the end:: + + python -m doctest -v example.py + + This will import :file:`example.py` as a standalone module and run + :func:`testmod` on it. Note that this may not work correctly if the + file is part of a package and imports other submodules from that package. + + If the file name does not end with :file:`.py`, :mod:`!doctest` infers + that it must be run with :func:`testfile` instead:: + + python -m doctest -v example.txt + +.. option:: -o, --option